The generated endpoints attach to the shared builder. You add custom queries and mutations the same way. Define fields on the builder, and they join the schema the server serves.
1
2
3
4
5
6
7
8
import { builder } from "@lakeql/api/builder"
builder.queryField("ping", (t) =>
t.string({
resolve: () => "pong",
})
)
Because it is the same builder, your custom fields get the same facilities as the generated ones. That covers the scope-auth scopes, the validation plugin, and the registered scalar and comparison types.
Two Prerequisites #
Custom fields do not reach the served schema by themselves:
-
Import your module before
startServer(). The server discovers schema modules by globbing the generatedquery-schema/mutation-schemafiles under its schema path. It does not import arbitrary files. A module likesrc/custom-fields.tsis only included if your entry point imports it before starting the server, or if you name it to match the glob.1 2 3
import "./custom-fields" // registers the builder fields await server.startServer() -
The
Mutationroot type exists only when a generatedmutation-schemafile is present. If your project has no generated mutations,builder.mutationField(...)has noMutationtype to attach to and Pothos throws "Mutation type not defined". Add a generated mutation first, or register the mutation type yourself.
Authorization #
Declare the scopes a custom field requires through Pothos's authScopes field option. For example, require an authenticated user, or a read permission on a particular table. See scope authorization.
Validation #
Attach a Zod schema to an argument via its validate option to validate input before the resolver runs. See input validation.
Accessing Data #
Resolvers reach the runtime through the GraphQL context. It exposes getReadStrategy(name) and getWriteStrategy(name). There is no context.runtime.
1
2
3
4
5
6
7
8
9
10
11
builder.queryField("orderCount", (t) =>
t.int({
resolve: async (_root, _args, context) => {
const strategy = context.getReadStrategy("warehouse")
// use the strategy to read, the same path generated resolvers take
// ...
return count
},
})
)