GraphQL API Monitoring
GraphQL APIs require specialized monitoring. Unlike REST endpoints, GraphQL can return 200 OK with errors in the response body. APIAssert provides first-class GraphQL monitoring to catch issues traditional monitors miss.
The Problem
GraphQL monitoring has unique challenges:
- 200 OK with errors — Server returns success, but
errorsarray is populated - Partial responses — Some fields resolve, others fail
- N+1 queries — Performance degrades without obvious errors
- Schema changes — Breaking changes aren't caught by status codes
- Resolver failures — Individual field resolution can fail silently
How APIAssert Helps
Execute Real Queries
APIAssert sends actual GraphQL queries, not just HTTP requests:
Monitor: User Profile Query
Query:
query GetUser($id: ID!) {
user(id: $id) {
id
email
profile {
name
avatar
}
}
}
Variables: {"id": "user_123"}
Detect GraphQL Errors
Assert that the errors array is empty:
Assertions:
✓ $.errors does not exist
✓ $.data.user exists
✓ $.data.user.email contains "@"
Monitor Mutations
Test that mutations work correctly:
Monitor: Create Post Mutation
Query:
mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
status
}
}
Variables: {"input": {"title": "Test", "content": "..."}}
Assertions:
✓ $.errors does not exist
✓ $.data.createPost.id exists
✓ $.data.createPost.status == "draft"
GraphQL-Specific Assertions
No Errors
The most important GraphQL assertion:
// Bad response (200 OK but has errors):
{
"data": null,
"errors": [
{
"message": "User not found",
"path": ["user"]
}
]
}
Assertion: $.errors must not exist
Data Structure
Validate the expected data structure:
// Expected response:
{
"data": {
"users": [
{"id": "1", "name": "Alice"},
{"id": "2", "name": "Bob"}
]
}
}
Assertions:
$.data.usersmust be array$.data.users.lengthmust be > 0$.data.users[0].idmust exist
Partial Failures
Some fields might fail while others succeed:
// Partial failure:
{
"data": {
"user": {
"id": "1",
"posts": null // Failed to resolve
}
},
"errors": [
{"message": "Failed to fetch posts", "path": ["user", "posts"]}
]
}
Assertions:
$.data.user.postsmust exist (catches null)$.errorsmust not exist
Real-World Examples
Monitor a Public GraphQL API
Monitor: GitHub GraphQL API
URL: https://api.github.com/graphql
Method: POST
Headers:
Authorization: Bearer $GITHUB_TOKEN
Body:
query: |
query {
viewer {
login
repositories(first: 5) {
nodes {
name
}
}
}
}
Assertions:
✓ $.errors does not exist
✓ $.data.viewer.login exists
✓ $.data.viewer.repositories.nodes.length > 0
✓ Response time < 2000ms
Monitor an E-commerce GraphQL API
Monitor: Product Catalog Query
Query:
query Products($first: Int!) {
products(first: $first) {
edges {
node {
id
name
price
inventory {
quantity
}
}
}
}
}
Variables: {"first": 10}
Assertions:
✓ $.errors does not exist
✓ $.data.products.edges.length > 0
✓ $.data.products.edges[0].node.price > 0
✓ $.data.products.edges[0].node.inventory.quantity >= 0
Monitor Authentication
Monitor: Auth Query
Query:
query Me {
me {
id
email
role
permissions
}
}
Headers:
Authorization: Bearer $TEST_USER_TOKEN
Assertions:
✓ $.errors does not exist
✓ $.data.me.id exists
✓ $.data.me.role in ["user", "admin"]
Common GraphQL Monitoring Patterns
Schema Health Check
Query introspection to verify schema is available:
query IntrospectionQuery {
__schema {
types {
name
}
}
}
Assertions:
$.data.__schema.types.length> 0
Resolver Performance
Monitor specific resolvers that are performance-critical:
query SlowResolver {
analytics {
dailyStats(days: 7) {
date
value
}
}
}
Assertions:
- Response time < 3000ms
$.data.analytics.dailyStats.length== 7
Subscription Health (via HTTP)
If you expose subscription health:
GET /graphql/subscriptions/health
Assertions:
✓ $.connected == true
✓ $.activeSubscriptions >= 0
Best Practices
Monitor Critical Paths
Focus on queries that impact users:
| Priority | Query Type | Example |
|---|---|---|
| Critical | Authentication | me, currentUser |
| Critical | Core data | products, orders |
| High | Search | searchProducts |
| Medium | Analytics | dashboardStats |
Use Realistic Variables
Test with production-like data:
// Good: Realistic variables
{"userId": "user_abc123", "limit": 10}
// Bad: Minimal testing
{"userId": "1", "limit": 1}
Monitor from Multiple Regions
GraphQL performance can vary by region, especially with:
- CDN caching
- Database proximity
- Resolver complexity
Test Error Handling
Intentionally test error cases:
Monitor: Invalid ID Handling
Query: user(id: "invalid_id") { id }
Assertions:
✓ Status code == 200
✓ $.errors[0].message contains "not found"
This ensures your error handling works correctly.
Track Response Times
GraphQL queries can be complex. Track performance:
Assertions:
✓ Response time < 500ms (simple queries)
✓ Response time < 2000ms (complex queries)
✓ Response time < 5000ms (analytics queries)
Alert Configuration
Critical
Condition: $.errors exists on core queries
Action: Page on-call
Reason: Users can't access data
Performance
Condition: Response time > 3000ms
Action: Slack alert
Reason: User experience degrading
Schema Issues
Condition: Introspection query fails
Action: Email engineering
Reason: Schema may be broken
Getting Started
- Identify critical queries — What queries do users rely on?
- Create monitors — Start with authentication and core data
- Add error assertions — Always check
$.errorsdoesn't exist - Add data assertions — Verify expected structure
- Monitor performance — Set response time thresholds
Related Features
- Response Validation — Learn more about assertions
- Multi-Region Monitoring — Check from multiple locations