LakeQL
Overview
  • Introduction
Server Setup
  • createApiServer
  • defineConfig
  • Yoga Configuration
Authentication
  • JWT Authentication
  • Permissions
  • Scope Authorization
Schema Builder
  • Builder Configuration
  • Scalar Types
  • Comparison Types
  • Pagination
  • Input Validation
Customization
  • Custom Queries & Mutations
  • Extending Core
  • CORS Configuration
GitHub
LakeQL
  1. API
  2. Schema Builder
  3. Input Validation

On this page

  1. How it works
  2. Error response format
  3. Built-in validation
  4. Adding validation to custom inputs
  5. Validation on query arguments

Input Validation

Validate GraphQL input fields using Zod schemas via the Pothos ValidationPlugin.

LakeQL integrates Pothos's ValidationPlugin with Zod to validate input arguments before they reach your resolvers. Invalid inputs return a structured VALIDATION_FAILED error with detailed issues.

How it works #

The ValidationPlugin is registered on the shared builder and uses Zod schemas to validate input field values. When validation fails, a custom error handler formats the response with error code 200 (VALIDATION_FAILED) and the list of Zod issues.

Error response format #

When validation fails, the GraphQL error includes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  "errors": [
    {
      "message": "Validation failed",
      "extensions": {
        "code": "VALIDATION_FAILED",
        "http": { "status": 400 },
        "additionalInformation": [
          {
            "message": "Value must be less than or equal to 2000",
            "path": ["perPage"]
          }
        ]
      }
    }
  ]
}

Built-in validation #

The Paging input type uses validation to enforce perPage limits:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { z } from "zod"
import { builder, getMaxRecordsPerPage } from "@lakeql/api/builder"

const Paging = builder.inputType("Paging", {
  fields: (t) => ({
    page: t.int({ defaultValue: 1 }),
    perPage: t.int({
      defaultValue: 100,
      validate: z
        .number()
        .min(1)
        .refine((value) => value <= getMaxRecordsPerPage(), {
          message: `Value must be less than or equal to ${getMaxRecordsPerPage()}`,
        }),
    }),
  }),
})

Adding validation to custom inputs #

Use the validate option on any input field to attach a Zod schema:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { z } from "zod"
import { builder } from "@lakeql/api/builder"

const CreateUserInput = builder.inputType("CreateUserInput", {
  fields: (t) => ({
    email: t.string({
      required: true,
      validate: z.string().email("Must be a valid email address"),
    }),
    name: t.string({
      required: true,
      validate: z.string().min(2).max(100),
    }),
    age: t.int({
      validate: z.number().min(0).max(150),
    }),
  }),
})

Validation on query arguments #

You can also validate query-level arguments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import { z } from "zod"
import { builder } from "@lakeql/api/builder"

builder.queryField("search", (t) =>
  t.field({
    type: ["String"],
    args: {
      query: t.arg.string({
        required: true,
        validate: z
          .string()
          .min(3, "Search query must be at least 3 characters"),
      }),
      limit: t.arg.int({
        defaultValue: 10,
        validate: z.number().min(1).max(100),
      }),
    },
    resolve: (_parent, args) => {
      // args.query is guaranteed to be at least 3 chars
      // args.limit is guaranteed to be between 1 and 100
      return [`Result for: ${args.query}`]
    },
  })
)

Previous page

Pagination

Next page

Customization

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26