Use Case

GraphQL API Monitoring

Keep your GraphQL APIs reliable

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 errors array 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.users must be array
  • $.data.users.length must be > 0
  • $.data.users[0].id must 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.posts must exist (catches null)
  • $.errors must 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

  1. Identify critical queries — What queries do users rely on?
  2. Create monitors — Start with authentication and core data
  3. Add error assertions — Always check $.errors doesn't exist
  4. Add data assertions — Verify expected structure
  5. Monitor performance — Set response time thresholds

Related Features