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
dataanderrors. - 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.