Input Directives
GraphQL doesn't include a built-in way to mutate input values via directives — the spec only covers schema-side transforms. createInputDirective from @baeta/core fills the gap with a small API for reading and writing input values before they reach the resolver.
Target types
Each input directive declares what shape of input it operates on:
scalar— primitive values (numbers, strings, booleans).list— array values.object— complex object inputs.
Defining the directive
Declare the directive in the schema:
src/modules/directives/input-directives.gql
directive @increment(by: Int!) on INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION
type Query {
testIncrementDirective(value: Int! @increment(by: 1)): Int!
}
Implementing the directive
createInputDirective<DirectiveArgs, Context> takes two type parameters:
DirectiveArgs— the shape of the directive's arguments in the schema.directive @increment(by: Int!) …⇒{ by: number }.Context— your application's GraphQL context type. Used to typectxinsideresolve.
Register the directive on the module with $directive (same place schema transformers go):
src/modules/custom-input-directive/index.ts
import { createInputDirective } from "@baeta/core";
import type { Context } from "../../types/context.ts";
import { CustomInputDirectiveModule } from "./typedef.ts";
const { Query } = CustomInputDirectiveModule;
const incrementDirective = createInputDirective<{ by: number }, Context>({
name: "increment",
target: "scalar",
resolve: ({ directiveConfig, getValue, setValue }) => {
const value = getValue();
if (typeof value === "number") {
setValue(value + directiveConfig.by);
}
},
});
const queryResolver = Query.$fields({
testIncrementDirective: Query.testIncrementDirective.resolve(({ args }) => {
return args.value;
}),
});
export default CustomInputDirectiveModule
.$directive(incrementDirective)
.$schema({
Query: queryResolver,
});
How it works
The directive runs before the resolver:
getValue()reads the incoming input value.- Your logic computes the new value.
setValue()replaces it. The resolver sees the new value as if it had been sent that way.
Usage
query {
testIncrementDirective(value: 5) {
# value will be incremented to 6 before reaching the resolver
}
}
Use input directives for validation, normalization (trim, lowercase), unit conversion, and any other pre-resolver transform.
See the directives example for runnable code.