Aller au contenu

Resolvers

The easiest way to get started is to use buildSchema or buildTypeDefsAndResolvers from @lib/type-graphql-query. These functions will automatically create a CRUD resolver for you based on the options you provide.

When you pass resolver options to buildSchema or buildTypeDefsAndResolvers, a CRUD resolver will be automatically generated for each DTO you specify.

import { buildTypeDefsAndResolvers } from '@lib/type-graphql-query';
import { Product } from './dto/product.type';
import { product as productTable } from '@lib/db';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
{
DTOClass: Product,
EntityClass: productTable,
enableTotalCount: true,
},
],
// ... other options
});

When using auto-generated resolvers, the following methods will be exposed for your DTO:

  • {entityName} - Find a single entity by id (e.g., product)
  • {entityName}s - Filter, sort, and page entities (e.g., products)
  • createOne{EntityName} - Create a single entity (e.g., createOneProduct)
  • createMany{EntityNames} - Create multiple entities (e.g., createManyProducts)
  • updateOne{EntityName} - Update a single entity by id (e.g., updateOneProduct)
  • updateMany{EntityNames} - Update multiple entities using a filter (e.g., updateManyProducts)
  • upsertOne{EntityName} - Upsert a single entity (e.g., upsertOneProduct)
  • upsertMany{EntityNames} - Upsert multiple entities (e.g., upsertManyProducts)
  • deleteOne{EntityName} - Delete a single entity by id (e.g., deleteOneProduct)
  • deleteMany{EntityNames} - Delete multiple entities using a filter (e.g., deleteManyProducts)

You can read more about these methods in the Queries and Mutations documentation.

When defining auto-generated resolvers, you can specify a number of options to control your endpoints.

  • DTOClass - The DTO class that the resolver is for. All methods will use types derived from this class.
  • EntityClass - The entity class (usually a Drizzle table) that represents the database entity.
  • enableTotalCount? - When set to true, enables the totalCount field on cursor or offset connections.
  • enableAggregate? - When set to true, enables aggregate queries on the type and all relations.
  • enableSubscriptions? - Set to true to enable GraphQL subscriptions. See Subscriptions.
  • pagingStrategy? - The paging strategy to use: PagingStrategies.CURSOR or PagingStrategies.OFFSET.
  • CreateDTOClass - The input DTO to use for create mutations. See Create and Update DTOs.
  • create - Options to customize create endpoints:
    • disabled? - Set to true to disable create endpoints.
    • one? - Options for createOne endpoint:
      • name? - Custom name for the mutation.
      • description? - Description for the mutation.
      • authorize? - Authorization options. See Authorization.
    • many? - Options for createMany endpoint (same options as one).
  • UpdateDTOClass - The input DTO to use for update mutations.
  • update - Options to customize update endpoints:
    • disabled? - Set to true to disable update endpoints.
    • one? - Options for updateOne endpoint.
    • many? - Options for updateMany endpoint.
  • UpsertDTOClass - The input DTO to use for upsert mutations.
  • upsert - Options to customize upsert endpoints:
    • disabled? - Set to true to disable upsert endpoints.
    • one? - Options for upsertOne endpoint.
    • many? - Options for upsertMany endpoint.
  • delete - Options to customize delete endpoints:
    • disabled? - Set to true to disable delete endpoints.
    • useSoftDelete? - When set to true, uses soft delete instead of hard delete.
    • one? - Options for deleteOne endpoint.
    • many? - Options for deleteMany endpoint.
  • read - Options to customize read endpoints:
    • authorize? - Authorization options for read operations.
    • one? - Options for the single entity query.
    • many? - Options for the list query.

The simplest resolver configuration:

import { buildTypeDefsAndResolvers } from '@lib/type-graphql-query';
import { Product } from './dto/product.type';
import { product as productTable } from '@lib/db';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
{
DTOClass: Product,
EntityClass: productTable,
},
],
});

You can specify different DTOs for create and update operations:

import { buildTypeDefsAndResolvers } from '@lib/type-graphql-query';
import { Product } from './dto/product.type';
import { ProductInput } from './dto/product.input';
import { product as productTable } from '@lib/db';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
{
DTOClass: Product,
EntityClass: productTable,
UpsertDTOClass: ProductInput,
create: {
disabled: true, // Disable create endpoints
},
update: {
disabled: true, // Disable update endpoints
},
upsert: {
// Upsert endpoints will use ProductInput
},
},
],
});

You can disable specific endpoints:

import { buildTypeDefsAndResolvers } from '@lib/type-graphql-query';
import { User } from './dto/user.type';
import { user as userTable } from '@lib/db';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
{
DTOClass: User,
EntityClass: userTable,
create: {
disabled: true, // Disable all create endpoints
},
update: {
disabled: true, // Disable all update endpoints
},
delete: {
disabled: true, // Disable all delete endpoints
useSoftDelete: true, // Use soft delete if enabled
},
},
],
});

You can add authorization to your resolvers:

import { buildTypeDefsAndResolvers, Permission } from '@lib/type-graphql-query';
import { Product } from './dto/product.type';
import { product as productTable } from '@lib/db';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
{
DTOClass: Product,
EntityClass: productTable,
read: {
authorize: Permission('product.view'),
},
create: {
authorize: Permission('product.create'),
},
update: {
authorize: Permission('product.update'),
},
delete: {
authorize: Permission('product.delete'),
},
},
],
auth: {
// Authorization configuration
// See Authorization documentation
},
});

For more information about authorization, see the Authorization documentation.

Here’s a complete example with all options:

import { buildTypeDefsAndResolvers, Permission, AllOf } from '@lib/type-graphql-query';
import { Product } from './dto/product.type';
import { ProductInput } from './dto/product.input';
import { ProductAggregate } from './dto/product-aggregate.type';
import { product as productTable } from '@lib/db';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
{
DTOClass: Product,
EntityClass: productTable,
UpsertDTOClass: ProductInput,
enableTotalCount: true,
enableAggregate: true,
AggregateDTOClass: ProductAggregate,
enableSubscriptions: true,
read: {
authorize: Permission('product.view'),
},
create: {
disabled: true,
authorize: Permission('product.create'),
},
update: {
disabled: true,
authorize: Permission('product.update'),
},
delete: {
disabled: false,
useSoftDelete: true,
authorize: Permission('product.delete'),
},
upsert: {
authorize: AllOf(Permission('product.create'), Permission('product.update')),
},
},
],
// ... other schema options
});

You can organize your resolvers in separate modules:

product/product.module.ts
import { TypeGraphqlQueryOptions } from '@lib/type-graphql-query';
import { Product } from './dto/product.type';
import { ProductInput } from './dto/product.input';
import { product as productTable } from '@lib/db';
const resolvers = [
{
DTOClass: Product,
EntityClass: productTable,
UpsertDTOClass: ProductInput,
enableTotalCount: true,
// ... other options
},
] satisfies TypeGraphqlQueryOptions['resolvers'];
export default resolvers;

Then import them in your schema:

create-schema.ts
import { buildTypeDefsAndResolvers } from '@lib/type-graphql-query';
import productModuleResolvers from './product/product.module';
import userModuleResolvers from './user/user.module';
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
...productModuleResolvers,
...userModuleResolvers,
// ... other resolvers
],
// ... other options
});

You can also create custom resolvers alongside auto-generated ones. Simply pass your custom resolver class to the resolvers array:

import { buildTypeDefsAndResolvers } from '@lib/type-graphql-query';
import { Resolver, Query } from '@lib/type-graphql';
import { Product } from './dto/product.type';
import { product as productTable } from '@lib/db';
@Resolver(() => Product)
export class ProductResolver {
@Query(() => [Product])
async featuredProducts(): Promise<Product[]> {
// Custom implementation
}
}
const { resolvers, typeDefs } = await buildTypeDefsAndResolvers({
resolvers: [
ProductResolver, // Custom resolver
{
DTOClass: Product,
EntityClass: productTable,
},
],
});