Error Handling¶
When you make a request to the Dxtra API, you may encounter errors. This guide explains the different types of errors and how to handle them.
HTTP Status Codes¶
The Dxtra API uses standard HTTP status codes to indicate the success or failure of a request.
| Code | Description |
|---|---|
200 OK | The request was successful |
400 Bad Request | Invalid request body or parameters |
401 Unauthorized | Missing or invalid authentication token |
403 Forbidden | Authenticated user lacks permission for the requested action |
404 Not Found | The requested resource does not exist |
429 Too Many Requests | Rate limit exceeded. See Rate Limits |
500 Internal Server Error | Unexpected server error |
GraphQL Errors¶
When you make a request to the GraphQL API, you may receive a 200 OK status code with an errors array in the response body. This indicates an error processing your GraphQL query.
GraphQL Response Patterns¶
Dxtra's GraphQL API uses different response patterns depending on the operation type:
Many GraphQL actions follow a status/message/data pattern:
{
"data": {
"generateDataControllerDID": {
"status": "success",
"message": "generateDataControllerDID",
"data": {
"dataControllerId": "123e4567-e89b-12d3-a456-426614174000",
"did": "did:dep:2135944ab870c8c5f44d4ca3da8550c5fbae6311318db8f9480b5dae5033d32a"
}
}
}
}
Actions using this pattern:
generateDataControllerDIDgenerateDataSubjectDIDreportDataControllersComplianceIssuesreportDataSubjectsRightsRequestsloginUserTagManager
Some actions return data directly without status wrappers:
Always check your specific action's response format using GraphQL introspection or the Actions Reference.
Common GraphQL Error Examples¶
Error Handling Best Practices¶
1. Comprehensive Error Detection¶
const executeGraphQLQuery = async (query, variables = {}) => {
try {
const response = await fetch('https://api.dxtra.ai/v1/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${jwtToken}`,
'X-Hasura-Role': 'user'
},
body: JSON.stringify({ query, variables })
});
// Check HTTP status first
if (!response.ok) {
if (response.status === 401) {
throw new Error('AUTH_EXPIRED');
}
throw new Error(`HTTP_${response.status}: ${response.statusText}`);
}
const result = await response.json();
// Check for GraphQL errors
if (result.errors && result.errors.length > 0) {
const errorMessage = result.errors[0].message;
const errorCode = result.errors[0].extensions?.code;
throw new Error(`GRAPHQL_ERROR: ${errorCode || 'UNKNOWN'} - ${errorMessage}`);
}
// For actions, check status field if present
const actionData = Object.values(result.data || {})[0];
if (actionData && actionData.status === 'error') {
throw new Error(`ACTION_ERROR: ${actionData.message}`);
}
return result.data;
} catch (error) {
console.error('GraphQL query failed:', error.message);
throw error;
}
};
2. Retry Logic with Exponential Backoff¶
const executeWithRetry = async (operation, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
const isRetryable = error.message.includes('HTTP_5') ||
error.message.includes('AUTH_EXPIRED');
if (!isRetryable || attempt === maxRetries) {
throw error;
}
// Exponential backoff: 1s, 2s, 4s
const delay = Math.pow(2, attempt - 1) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
// Refresh auth token if expired
if (error.message.includes('AUTH_EXPIRED')) {
jwtToken = await getJwtFromApiKey(apiKey);
}
}
}
};
3. User-Friendly Error Messages¶
const translateErrorForUser = (error) => {
const errorMap = {
'AUTH_EXPIRED': 'Your session has expired. Please refresh the page.',
'GRAPHQL_ERROR: validation-failed': 'Invalid request. Please check your input.',
'HTTP_429': 'Too many requests. Please wait a moment and try again.',
'HTTP_500': 'Service temporarily unavailable. Please try again later.',
'ACTION_ERROR': 'Operation failed. Please check your input and try again.'
};
for (const [pattern, message] of Object.entries(errorMap)) {
if (error.message.includes(pattern)) {
return message;
}
}
return 'An unexpected error occurred. Please contact support if this persists.';
};
Common Error Scenarios¶
| Error Type | Cause | Solution |
|---|---|---|
| 401 Unauthorized | Missing/invalid JWT token | Refresh authentication |
| 403 Forbidden | Insufficient role permissions | Check X-Hasura-Role header |
| Field not found | Using wrong field names | Use camelCase field names (e.g., dataControllers) |
| Rate limit exceeded | Too many requests | Implement exponential backoff |
| Action status: error | Business logic failure | Check action-specific error message |
Monitoring and Debugging¶
Request/Response Logging¶
if (process.env.NODE_ENV === 'development') {
console.log('GraphQL Request:', { query, variables });
console.log('GraphQL Response:', result);
}
Production Error Tracking¶
For production applications, implement proper error monitoring:
- Sentry -- Automatic error tracking and performance monitoring
- LogRocket -- Session replay for debugging user issues
- Custom logging -- Log API errors with context for debugging
Rate Limiting
Webhook endpoints are rate limited to 1000 requests per 15 minutes per IP. GraphQL actions called via the API are not rate limited. See Rate Limits for details.