Arguments chaining
Input arguments of the resolver can be chained, enabling the creation of complex types or the determination of types prior to the execution of the resolver function. This capability is particularly useful, for instance, within middleware functions.
const personWithFirstNameResolver = resolver.args(
Type.Object({ person: Type.Object({ firstName: Type.String() }) }),
);
const personResolver = personWithFirstNameResolver.args(
Type.Object({
person: Type.Object({ lastName: Type.String() }),
}),
);
const testQuery = personResolver
.output(Type.String())
.query(
({ input /* { person: { firstName: string; lastName: string; } } */ }) => {
return `Hello, ${input.person.firstName} ${input.person.lastName}`;
},
);
The types are merged into one. It is using the Type.Intersection
in the background.
Using arguments chaining with middleware
Harnessing argument chaining allows for the validation of input within the middleware, ensuring that inputs are validated before the resolver begins its execution.
const personResolver = resolver.args(
Type.Object({ person: Type.Object({ firstName: Type.String() }) }),
);
const personWithLogResolver = personResolver.use(
({ input /* { person: { firstName: string } } */, ctx, next }) => {
console.log('Persons first name: ', input.person.firstName);
return next();
},
);
const testQuery = personWithLogResolver
.args(
Type.Object({
person: Type.Object({
firstName: Type.String(), // <- can be there but it does not have to
lastName: Type.String(),
}),
}),
)
.output(Type.String())
.query(
({
input /* { person: { firstName: string; lastName: string; } } */,
ctx /* { personFirstName: string } */,
}) /* string */ => {
return `Hello, ${input.person.firstName} ${input.person.lastName}`;
},
);
Indeed, the ability to access the input safely stems from its validation through the arguments. In the given illustration, we log the first name and subsequently pass it into a context. This contextual information enables the query to utilize the assigned person's first name seamlessly.
It's important to note that while future arguments in the argument chaining sequence can extend the existing validation schema, they are not obligated to do so. This flexibility ensures adaptability to evolving requirements without imposing unnecessary constraints.
import { personSchema } from './validation';
const loggerResolver = resolver
.args(
Type.Object({
email: Type.String({
format: 'email',
}),
}),
)
.use(({ input, ctx, next }) => {
console.log('Log the email: ', input.email);
return next(ctx);
});
loggerResolver.args(personSchema).query({
// ...
});
The personSchema
can have email validation in its definition.