GraphQL Documentation

GraphQL API Reference

This sample demonstrates GraphQL API documentation: schema overview, query examples, mutations, error handling, and pagination patterns.

Endpoint

POST https://api.example.com/graphql

All GraphQL operations use a single endpoint. Queries and mutations are sent as POST requests with a JSON body.

Authentication

Include your API key in the Authorization header:

Authorization: Bearer your-api-key

Making Requests

curl -X POST https://api.example.com/graphql \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { viewer { id email } }"
  }'

Schema Overview

Core Types

type User {
  id: ID!
  email: String!
  name: String
  createdAt: DateTime!
  projects: [Project!]!
  role: Role!
}

type Project {
  id: ID!
  name: String!
  description: String
  owner: User!
  members: [User!]!
  createdAt: DateTime!
  updatedAt: DateTime!
  status: ProjectStatus!
}

enum ProjectStatus {
  ACTIVE
  ARCHIVED
  DELETED
}

enum Role {
  ADMIN
  MEMBER
  VIEWER
}

Queries

Get Current User

query {
  viewer {
    id
    email
    name
    role
  }
}

Response

{
  "data": {
    "viewer": {
      "id": "user_123",
      "email": "user@example.com",
      "name": "Jane Doe",
      "role": "ADMIN"
    }
  }
}

Get Project with Members

GraphQL lets you fetch related data in a single request:

query GetProject($id: ID!) {
  project(id: $id) {
    id
    name
    status
    owner {
      id
      name
    }
    members {
      id
      name
      email
    }
  }
}

Variables

{
  "id": "proj_abc123"
}

Response

{
  "data": {
    "project": {
      "id": "proj_abc123",
      "name": "My Project",
      "status": "ACTIVE",
      "owner": {
        "id": "user_123",
        "name": "Jane Doe"
      },
      "members": [
        {"id": "user_456", "name": "John Smith", "email": "john@example.com"}
      ]
    }
  }
}

List Projects with Pagination

We use cursor-based pagination following the Relay specification:

query ListProjects($first: Int!, $after: String) {
  projects(first: $first, after: $after) {
    edges {
      cursor
      node {
        id
        name
        status
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
    totalCount
  }
}

Variables (first page)

{
  "first": 10,
  "after": null
}

Variables (next page)

{
  "first": 10,
  "after": "cursor_from_previous_response"
}

Mutations

Create Project

mutation CreateProject($input: CreateProjectInput!) {
  createProject(input: $input) {
    project {
      id
      name
      status
      createdAt
    }
    errors {
      field
      message
    }
  }
}

Variables

{
  "input": {
    "name": "New Project",
    "description": "Project description"
  }
}

Success Response

{
  "data": {
    "createProject": {
      "project": {
        "id": "proj_new123",
        "name": "New Project",
        "status": "ACTIVE",
        "createdAt": "2023-11-08T10:00:00Z"
      },
      "errors": []
    }
  }
}

Validation Error Response

{
  "data": {
    "createProject": {
      "project": null,
      "errors": [
        {"field": "name", "message": "Name is required"},
        {"field": "name", "message": "Name must be at least 3 characters"}
      ]
    }
  }
}

Update Project

mutation UpdateProject($id: ID!, $input: UpdateProjectInput!) {
  updateProject(id: $id, input: $input) {
    project {
      id
      name
      updatedAt
    }
    errors {
      field
      message
    }
  }
}

Delete Project

mutation DeleteProject($id: ID!) {
  deleteProject(id: $id) {
    success
    errors {
      message
    }
  }
}

Error Handling

GraphQL returns errors in a standardized format:

Query Errors

{
  "data": null,
  "errors": [
    {
      "message": "Project not found",
      "locations": [{"line": 2, "column": 3}],
      "path": ["project"],
      "extensions": {
        "code": "NOT_FOUND",
        "requestId": "req_abc123"
      }
    }
  ]
}

Common Error Codes

  • UNAUTHENTICATED — Invalid or missing API key
  • FORBIDDEN — Insufficient permissions for this operation
  • NOT_FOUND — Resource does not exist
  • VALIDATION_ERROR — Input validation failed
  • RATE_LIMITED — Too many requests
  • INTERNAL_ERROR — Server error (include requestId when reporting)

Best Practices

  • Request only what you need. GraphQL lets you specify exact fields. Avoid over-fetching.
  • Use variables. Never interpolate values into query strings. Use GraphQL variables for safety and caching.
  • Handle partial data. GraphQL can return partial results with errors. Check both data and errors.
  • Use fragments for reuse. Define fragments for commonly requested field sets.
  • Paginate large lists. Always use pagination for list queries to avoid timeouts.

Fragment Example

fragment UserFields on User {
  id
  name
  email
}

query {
  viewer {
    ...UserFields
  }
  project(id: "proj_123") {
    owner {
      ...UserFields
    }
  }
}

Rate Limiting

GraphQL queries are rate-limited based on complexity, not just request count:

  • Each field costs 1 point
  • List fields cost 1 + (first × child cost)
  • Default limit: 10,000 points per minute

Include the X-Query-Cost header in responses to monitor usage.

Related Samples

This is a sample article to demonstrate how I write.