> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# GraphQL

> GraphQL query validation middleware for securing GraphQL APIs.

## Overview

The `graphql` middleware provides GraphQL query validation and security features including depth limiting, complexity analysis, introspection control, and field blocking.

Use it when you need:

* Query depth and complexity validation
* Introspection query control
* Field-level access control
* Operation allowlisting
* Protection against malicious queries

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/graphql"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Use default validation (max depth: 10, max complexity: 100)
app.Use(graphql.New())

app.Post("/graphql", yourGraphQLHandler)
```

## Configuration

### Options

| Option                 | Type                           | Default | Description                          |
| ---------------------- | ------------------------------ | ------- | ------------------------------------ |
| `MaxDepth`             | `int`                          | `10`    | Maximum query depth allowed          |
| `MaxComplexity`        | `int`                          | `100`   | Maximum query complexity allowed     |
| `DisableIntrospection` | `bool`                         | `false` | Disable introspection queries        |
| `AllowedOperations`    | `[]string`                     | `nil`   | Whitelist of allowed operation names |
| `BlockedFields`        | `[]string`                     | `nil`   | List of fields to block              |
| `ErrorHandler`         | `func(*mizu.Ctx, error) error` | `nil`   | Custom error handler                 |

## Examples

### Basic Setup

```go theme={null}
// Use with default settings
app.Use(graphql.New())

app.Post("/graphql", yourGraphQLHandler)
```

### Custom Depth and Complexity Limits

```go theme={null}
app.Use(graphql.WithOptions(graphql.Options{
    MaxDepth:      5,
    MaxComplexity: 50,
}))
```

### Production Configuration

```go theme={null}
// Production-ready settings with introspection disabled
app.Use(graphql.Production())
```

### Disable Introspection

```go theme={null}
// Block __schema and __type queries
app.Use(graphql.NoIntrospection())
```

### Block Sensitive Fields

```go theme={null}
// Prevent access to specific fields
app.Use(graphql.BlockFields("password", "secret", "apiKey"))
```

### Allowlist Operations

```go theme={null}
app.Use(graphql.WithOptions(graphql.Options{
    AllowedOperations: []string{"GetUser", "ListPosts", "CreateComment"},
}))
```

### Custom Error Handler

```go theme={null}
app.Use(graphql.WithOptions(graphql.Options{
    MaxDepth: 10,
    ErrorHandler: func(c *mizu.Ctx, err error) error {
        return c.JSON(http.StatusForbidden, map[string]any{
            "errors": []map[string]string{
                {"message": "Query validation failed", "detail": err.Error()},
            },
        })
    },
}))
```

## API Reference

### Functions

```go theme={null}
// New creates GraphQL validation middleware with default options
func New() mizu.Middleware

// WithOptions creates GraphQL validation middleware with custom options
func WithOptions(opts Options) mizu.Middleware

// MaxDepth creates middleware with a specific max depth
func MaxDepth(depth int) mizu.Middleware

// MaxComplexity creates middleware with a specific max complexity
func MaxComplexity(complexity int) mizu.Middleware

// NoIntrospection creates middleware that disables introspection
func NoIntrospection() mizu.Middleware

// Production creates middleware with production-ready settings
func Production() mizu.Middleware

// BlockFields creates middleware that blocks specific fields
func BlockFields(fields ...string) mizu.Middleware
```

### Error Types

```go theme={null}
const (
    ErrQueryTooDeep          = "query exceeds maximum depth"
    ErrQueryTooComplex       = "query exceeds maximum complexity"
    ErrIntrospectionDisabled = "introspection queries are disabled"
    ErrOperationNotAllowed   = "operation not allowed"
    ErrBlockedField          = "query contains blocked field"
)
```

## Technical Details

### Query Validation Process

The middleware validates GraphQL queries through the following process:

1. **Request Filtering**: Only processes POST requests with `application/json` content type
2. **Query Parsing**: Parses the request body into a `Query` structure containing:
   * `query`: The GraphQL query string
   * `operationName`: Named operation identifier
   * `variables`: Query variables map
3. **Validation Chain**: Applies validations in order:
   * Introspection check (if enabled)
   * Operation allowlist check (if configured)
   * Depth calculation and validation
   * Complexity calculation and validation
   * Blocked fields check (if configured)
4. **Body Restoration**: Restores the request body for downstream handlers

### Depth Calculation

Query depth is calculated by counting the maximum nesting level of braces `{}`:

* Tracks current depth using a counter
* Increments on `{`, decrements on `}`
* Records the maximum depth reached

Example:

```graphql theme={null}
{ users { posts { id } } }  // Depth: 3
```

### Complexity Calculation

Query complexity is estimated using:

* Count of field selections with braces: `\w+\s*(?:\([^)]*\))?\s*{`
* Plus total count of opening braces `{`

This provides a simple heuristic for query cost.

### Introspection Detection

Introspection queries are detected using regex pattern matching for:

* `__schema` - Schema introspection
* `__type` - Type introspection

### Implementation Notes

* The middleware preserves the request body after validation for downstream handlers
* Non-POST requests and non-JSON requests bypass validation
* Failed JSON parsing allows the request to pass through (handled by GraphQL server)
* Default limits provide reasonable protection for most applications

## Best Practices

* Disable introspection in production
* Set appropriate depth limits based on your schema
* Use complexity limits to prevent resource exhaustion
* Block sensitive fields at the middleware level
* Implement custom error handlers for better user experience
* Combine with rate limiting for additional protection

## Testing

### Test Coverage

| Test Case                              | Description                   | Expected Behavior                                                        |
| -------------------------------------- | ----------------------------- | ------------------------------------------------------------------------ |
| `TestNew`                              | Default middleware creation   | Accepts valid queries with default limits                                |
| `TestWithOptions_MaxDepth`             | Query depth validation        | Rejects queries exceeding max depth (4 > 2)                              |
| `TestWithOptions_MaxComplexity`        | Query complexity validation   | Rejects queries exceeding max complexity                                 |
| `TestWithOptions_DisableIntrospection` | Introspection blocking        | Blocks `__schema` and `__type` queries                                   |
| `TestWithOptions_BlockedFields`        | Field blocking                | Rejects queries containing blocked fields (password, secret)             |
| `TestSkipNonPOST`                      | GET request handling          | Allows non-POST requests to pass through                                 |
| `TestMaxDepth`                         | MaxDepth helper function      | Accepts queries within depth limit (2 ≤ 3)                               |
| `TestMaxComplexity`                    | MaxComplexity helper function | Accepts queries within complexity limit                                  |
| `TestNoIntrospection`                  | NoIntrospection helper        | Blocks `__type` introspection queries                                    |
| `TestProduction`                       | Production configuration      | Applies production settings (depth:10, complexity:100, no introspection) |
| `TestBlockFields`                      | BlockFields helper            | Blocks specified mutation fields (deleteMutation, adminAccess)           |
| `TestCustomErrorHandler`               | Custom error handling         | Uses custom error handler with HTTP 403 status                           |

## Security Considerations

### Query Depth Attacks

Deep nested queries can cause exponential computation:

```graphql theme={null}
{ users { friends { friends { friends { ... } } } } }
```

Mitigation: Set `MaxDepth` based on your schema's maximum legitimate nesting.

### Query Complexity Attacks

Complex queries can exhaust server resources:

```graphql theme={null}
{ users { posts { comments { author { posts { comments { ... } } } } } } }
```

Mitigation: Use `MaxComplexity` to limit total query cost.

### Introspection Leaks

Introspection exposes your entire schema structure:

```graphql theme={null}
{ __schema { types { name fields { name } } } }
```

Mitigation: Disable introspection in production with `NoIntrospection()` or `Production()`.

### Sensitive Field Access

Prevent access to sensitive fields:

```graphql theme={null}
{ users { password ssn apiKey } }
```

Mitigation: Use `BlockFields()` to prevent access to sensitive data.

## Related Middlewares

* [jsonrpc](/middlewares/jsonrpc) - JSON-RPC support
* [ratelimit](/middlewares/ratelimit) - Rate limiting
* [timeout](/middlewares/timeout) - Request timeout
