GraphQL Request Batching¶
Execute multiple GraphQL operations in a single HTTP request to the GraphQL API.
Execution Model
The API executes batched queries sequentially and returns combined results. This reduces network round trips but does not provide parallel execution.
When to Use Batching¶
Batching is beneficial when you need to:
- Fetch data from multiple unrelated tables simultaneously
- Initialize application state requiring several independent queries
- Reduce network overhead in high-latency environments (mobile, edge networks)
Not recommended for:
- Operations that depend on each other (use sequential requests instead)
- Real-time updates (use subscriptions)
- Large bulk mutations (use
insert_manymutations with arrays)
Batch Request Format¶
The API accepts an array of GraphQL request objects:
[
{
"query": "query GetControllers { dataControllers { id title } }"
},
{
"query": "query GetSubjects($limit: Int!) { dataSubjects(limit: $limit) { id did } }",
"variables": { "limit": 10 }
}
]
Sequential Execution
The API processes batched queries in order. If query 2 depends on results from query 1, use separate requests instead.
Implementation Examples¶
TypeScript with graphql-request¶
import { GraphQLClient, gql } from 'graphql-request';
const client = new GraphQLClient('https://api.dxtra.ai/v1/graphql', {
headers: {
'Authorization': `Bearer ${jwt}`,
'X-Hasura-Role': 'user'
}
});
// Batch multiple queries
const results = await client.batchRequests([
{
document: gql`
query GetControllers {
dataControllers {
id
title
createdAt
}
}
`
},
{
document: gql`
query GetActiveSubjects($limit: Int!) {
dataSubjects(
limit: $limit
) {
id
did
}
}
`,
variables: { limit: 50 }
}
]);
// Access results by index
const controllers = results[0].data.dataControllers;
const subjects = results[1].data.dataSubjects;
Python with gql¶
from gql import Client, gql
from gql.transport.aiohttp import AIOHTTPTransport
import asyncio
# Create transport with authentication
transport = AIOHTTPTransport(
url='https://api.dxtra.ai/v1/graphql',
headers={
'Authorization': f'Bearer {jwt_token}',
'X-Hasura-Role': 'user'
}
)
client = Client(transport=transport, fetch_schema_from_transport=False)
# Define queries
query1 = gql("""
query GetControllers {
dataControllers {
id
title
createdAt
}
}
""")
query2 = gql("""
query GetRightsRequests($controllerId: uuid!) {
dataSubjectsRightsRequests(
where: {dataSubject: {dataControllerId: {_eq: $controllerId}}}
) {
id
requestType
status
}
}
""")
async def fetch_data():
# Execute queries concurrently (gql library doesn't support batch API)
async with client as session:
result1, result2 = await asyncio.gather(
session.execute(query1),
session.execute(query2, variable_values={'controllerId': controller_id})
)
return result1, result2
# Run async function
results = asyncio.run(fetch_data())
Python GraphQL Clients
The gql library does not provide a batch API. Use asyncio.gather() for concurrent execution of multiple queries.
Multiple Queries in a Single Document¶
The API also supports multiple root-level fields in a single GraphQL document:
This approach executes all fields and returns a single combined result object.
Practical Use Cases¶
Dashboard Data Loading¶
import { GraphQLClient, gql } from 'graphql-request';
async function loadDashboard(controllerID: string, jwt: string) {
const client = new GraphQLClient('https://api.dxtra.ai/v1/graphql', {
headers: {
'Authorization': `Bearer ${jwt}`,
'X-Hasura-Role': 'user'
}
});
const [overview, activities, requests] = await client.batchRequests([
{
document: gql`
query GetController($controllerID: uuid!) {
dataControllers(where: {id: {_eq: $controllerID}}) {
id
title
did
createdAt
}
}
`,
variables: { controllerID }
},
{
document: gql`
query GetActivities($controllerID: uuid!, $limit: Int!) {
dataProcessingActivities(
where: { dataSubject: { dataControllerId: { _eq: $controllerID } } }
limit: $limit
order_by: { triggeredAt: desc }
) {
id
typeId
triggeredAt
type {
label
}
}
}
`,
variables: { controllerID, limit: 10 }
},
{
document: gql`
query GetRequests($controllerID: uuid!) {
dataSubjectsRightsRequests(
where: {
dataSubject: { dataControllerId: { _eq: $controllerID } }
status: { _eq: "pending" }
}
) {
id
requestType
createdAt
}
}
`,
variables: { controllerID }
}
]);
return {
controller: overview.data.dataControllers,
recentActivities: activities.data.dataProcessingActivities,
pendingRequests: requests.data.dataSubjectsRightsRequests
};
}
GraphQL Fragments¶
Use fragments for reusable field sets across batched queries:
fragment DataSubjectCore on dataSubjects {
id
did
createdAt
}
query GetSubjectsWithActivities {
dataSubjects {
...DataSubjectCore
dataProcessingActivities(limit: 1, order_by: {triggeredAt: desc}) {
typeId
triggeredAt
}
}
}
Error Handling¶
The API returns errors for each failed query in the batch:
try {
const results = await client.batchRequests([
{ document: query1 },
{ document: query2 }
]);
// Check each result for errors
results.forEach((result, index) => {
if (result.errors) {
console.error(`Query ${index} failed:`, result.errors);
}
});
} catch (error) {
// Network or authentication error
console.error('Batch request failed:', error);
}
Common Issues¶
| Issue | Solution |
|---|---|
| Query timeout | Reduce query complexity or use pagination |
| Authentication failure | Verify JWT token and X-Hasura-Role header |
| Variable type mismatch | Ensure variables match schema types exactly |
| Network error | Check endpoint URL and network connectivity |
Alternative Approaches¶
GraphQL Aliases¶
Execute the same query multiple times with different arguments:
query MultipleControllers {
controller1: dataControllers(where: {id: {_eq: "uuid-1"}}) {
id
title
}
controller2: dataControllers(where: {id: {_eq: "uuid-2"}}) {
id
title
}
}
Next Steps¶
- Error Handling -- Implement robust error management
- Authentication -- Configure JWT and role-based access
- GraphQL Reference -- Complete schema documentation
- Performance Optimization -- Optimize query performance