Aller au contenu

Types

type-graphql-query provides a number of types. Most will be automatically generated for you when you create a resolver using buildSchema or buildTypeDefsAndResolvers. However, you can use many of the types in your own code for custom endpoints.

The following examples are based on the following ProductDTO:

import { ObjectType, ID, GraphQLISODateTime } from '@lib/type-graphql';
import { EnhancedField, IDField } from '@lib/type-graphql-query';
@ObjectType('Product')
export class ProductDTO {
@IDField(() => ID)
id!: string;
@EnhancedField(() => String)
name!: string;
@EnhancedField(() => Boolean)
canBeSold!: boolean;
@EnhancedField(() => GraphQLISODateTime)
createdAt!: Date;
@EnhancedField(() => GraphQLISODateTime)
updatedAt!: Date;
}

Args type used in read endpoints to allow filtering, paging, and sorting.

The QueryArgsType will generate an ArgsType that will require the user to provide three arguments.

  • filter? - A filter that should be used to find records. See FilterType
  • paging? - Options to page results.
  • sorting? - Optional array to allow sorting of results. See SortType.
import { QueryArgsType } from '@lib/type-graphql-query';
import { ArgsType } from '@lib/type-graphql';
import { ProductDTO } from './dto/product.dto';
@ArgsType()
export class ProductQuery extends QueryArgsType(ProductDTO) {}

The QueryArgsType function returns a class with static properties:

  • FilterType - The filter type for the DTO
  • SortType - The sort type for the DTO
  • PageType - The paging type (CursorPaging, OffsetPaging, or NonePaging)
  • ConnectionType - The connection type for the DTO
import { QueryArgsType } from '@lib/type-graphql-query';
import { ProductDTO } from './dto/product.dto';
export const ProductQueryArgs = QueryArgsType(ProductDTO);
// Access static types
export const ProductFilter = ProductQueryArgs.FilterType;
export const ProductSort = ProductQueryArgs.SortType;
export const ProductPaging = ProductQueryArgs.PageType;
export const ProductConnection = ProductQueryArgs.ConnectionType;

Implementation of connections. Useful for large result sets where the end user should be able to page through the results.

import { QueryArgsType } from '@lib/type-graphql-query';
import { ProductDTO } from './dto/product.dto';
export const ProductQueryArgs = QueryArgsType(ProductDTO);
export const ProductConnection = ProductQueryArgs.ConnectionType;

Cursor Connection Schema:

scalar ConnectionCursor
type ProductConnection {
pageInfo: PageInfo!
edges: [ProductEdge!]!
totalCount: Int
}
type ProductEdge {
node: Product!
cursor: ConnectionCursor!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: ConnectionCursor
endCursor: ConnectionCursor
}

Offset Connection Schema:

type ProductConnection {
pageInfo: OffsetPageInfo!
nodes: [Product!]!
totalCount: Int
}
type OffsetPageInfo {
hasNextPage: Boolean!
}

Response from updateMany mutations.

import { UpdateManyResponseType } from '@lib/type-graphql-query';
export const UpdateManyResponse = UpdateManyResponseType();

Schema:

type UpdateManyResponse {
updatedCount: Int!
}

Response from deleteMany mutations.

import { DeleteManyResponseType } from '@lib/type-graphql-query';
export const DeleteManyResponse = DeleteManyResponseType();

Schema:

type DeleteManyResponse {
deletedCount: Int!
}

GraphQL implementation of the Filter type.

The FilterType is dynamically created based on the fields in the DTO annotated with @EnhancedField({ filterable: true }).

Along with the dynamically created fields, filter also has the following static fields:

  • and - Allows for joining multiple Filters using an AND condition.
    For example, find all products that start with 'Chicken' AND can be sold.

    query {
    queryManyProduct(
    filter: { and: [{ name: { like: "Chicken%" } }, { canBeSold: { is: true } }] }
    ) {
    id
    name
    }
    }
  • or - Allows for joining multiple Filters using an OR condition.
    For example, find all products that (can be sold AND start with 'Chicken') OR (cannot be sold and end in 'Egg').

    query {
    queryManyProduct(
    filter: {
    or: [
    { name: { like: "Chicken%" }, canBeSold: { is: true } }
    { name: { like: "%Egg" }, canBeSold: { is: false } }
    ]
    }
    ) {
    id
    name
    }
    }
import { FilterType } from '@lib/type-graphql-query';
import { ProductDTO } from './dto/product.dto';
export const ProductFilter = FilterType(ProductDTO);

Schema:

input ProductFilter {
and: [ProductFilter!]
or: [ProductFilter!]
id: IDFilterComparison
name: StringFilterComparison
canBeSold: BooleanFilterComparison
createdAt: DateFilterComparison
updatedAt: DateFilterComparison
}
input IDFilterComparison {
is: Boolean
isNot: Boolean
eq: ID
neq: ID
gt: ID
gte: ID
lt: ID
lte: ID
like: ID
notLike: ID
iLike: ID
notILike: ID
in: [ID!]
notIn: [ID!]
}
input StringFilterComparison {
is: Boolean
isNot: Boolean
eq: String
neq: String
gt: String
gte: String
lt: String
lte: String
like: String
notLike: String
iLike: String
notILike: String
in: [String!]
notIn: [String!]
}
input BooleanFilterComparison {
is: Boolean
isNot: Boolean
}
input DateFilterComparison {
is: Boolean
isNot: Boolean
eq: DateTime
neq: DateTime
gt: DateTime
gte: DateTime
lt: DateTime
lte: DateTime
in: [DateTime!]
notIn: [DateTime!]
}

The SortType allows you to sort results.

NOTE This type is automatically created when using QueryArgsType.

For more comprehensive examples take a look at the Sorting Docs.

  • field - The field to sort on. This is an ENUM of fields defined in the DTO with @EnhancedField({ sortable: true }).
  • direction - The direction to sort the field ASC or DESC.
  • nulls? - On supported storage engines you can specify the null sort order NULLS_FIRST, NULLS_LAST
import { QueryArgsType } from '@lib/type-graphql-query';
import { ProductDTO } from './dto/product.dto';
export const ProductQueryArgs = QueryArgsType(ProductDTO);
export const ProductSort = ProductQueryArgs.SortType;

Schema:

input ProductSort {
field: ProductSortFields!
direction: SortDirection!
nulls: SortNulls
}
enum ProductSortFields {
id
name
canBeSold
createdAt
updatedAt
}
enum SortDirection {
ASC
DESC
}
enum SortNulls {
NULLS_FIRST
NULLS_LAST
}

Input type for createOne mutations.

NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.

NOTE Your DTO should be one that you want to use for input. For example you may not want to let the end user specify the createdAt or updatedAt fields so you would create a new DTO just for input.

import { CreateOneInputType } from '@lib/type-graphql-query';
import { InputType, Field } from '@lib/type-graphql';
import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')
export class ProductInputDTO {
@IsString()
@Field()
name!: string;
@IsBoolean()
@Field()
canBeSold!: boolean;
}
@InputType()
export class CreateOneProductInput extends CreateOneInputType('product', ProductInputDTO) {}

Schema:

input CreateOneProductInput {
product: ProductInput!
}
input ProductInput {
name: String!
canBeSold: Boolean!
}

Input type for createMany mutations.

NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.

NOTE Your DTO should be one that you want to use for input. For example you may not want to let the end user specify the createdAt or updatedAt fields so you would create a new DTO just for input.

import { CreateManyInputType } from '@lib/type-graphql-query';
import { InputType, Field } from '@lib/type-graphql';
import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')
export class ProductInputDTO {
@IsString()
@Field()
name!: string;
@IsBoolean()
@Field()
canBeSold!: boolean;
}
@InputType()
export class CreateManyProductsInput extends CreateManyInputType('products', ProductInputDTO) {}

Schema:

input CreateManyProductsInput {
products: [ProductInput!]!
}
input ProductInput {
name: String!
canBeSold: Boolean!
}

InputType for updateOne mutations.

The UpdateOneInputType will generate an InputType that will require the user to provide two fields.

  • id - The id of the record to update
  • update - A record with fields to update.
import { UpdateOneInputType } from '@lib/type-graphql-query';
import { InputType, Field } from '@lib/type-graphql';
import { IsOptional, IsString, IsBoolean } from 'class-validator';
import { ProductDTO } from './dto/product.dto';
@InputType('ProductUpdateInput')
export class ProductUpdateDTO {
@IsOptional()
@IsString()
@Field({ nullable: true })
name?: string;
@IsOptional()
@IsBoolean()
@Field({ nullable: true })
canBeSold?: boolean;
}
@InputType()
export class UpdateOneProductInput extends UpdateOneInputType(ProductDTO, ProductUpdateDTO) {}

Schema:

input UpdateOneProductInput {
id: ID!
update: ProductUpdateInput!
}
input ProductUpdateInput {
name: String
canBeSold: Boolean
}

Input type for updateMany mutations.

The UpdateManyInputType will generate an InputType that will require the user to provide two arguments.

  • filter - The filter that should be used to find records to update. See FilterType
  • update - The update to apply to each record found.

NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.

NOTE Your DTO should be one that you want to use for input. For example you may not want to let the end user specify the createdAt or updatedAt fields so you would create a new DTO just for input.

In this example we use the read DTO for the FilterType, and a different update DTO.

import { UpdateManyInputType, FilterType } from '@lib/type-graphql-query';
import { InputType, Field } from '@lib/type-graphql';
import { IsOptional, IsString, IsBoolean } from 'class-validator';
import { ProductDTO } from './dto/product.dto';
@InputType('ProductUpdate')
export class ProductUpdateDTO {
@IsOptional()
@IsString()
@Field({ nullable: true })
name?: string;
@IsOptional()
@IsBoolean()
@Field({ nullable: true })
canBeSold?: boolean;
}
@InputType()
export class UpdateManyProductsInput extends UpdateManyInputType(
ProductDTO, // filter
ProductUpdateDTO, // update DTO
) {}

Schema:

input UpdateManyProductsInput {
filter: ProductFilter!
update: ProductUpdate!
}
input ProductUpdate {
name: String
canBeSold: Boolean
}

InputType for deleteOne mutations.

The DeleteOneInputType will generate an InputType that will require the user to provide the id of the record to delete.

import { DeleteOneInputType } from '@lib/type-graphql-query';
import { InputType } from '@lib/type-graphql';
import { ProductDTO } from './dto/product.dto';
@InputType()
export class DeleteOneProductInput extends DeleteOneInputType(ProductDTO) {}

Schema:

input DeleteOneProductInput {
id: ID!
}

Input type for deleteMany mutations.

The DeleteManyInputType will generate an InputType that will require the user to provide:

  • filter - A filter used to find records to delete. See FilterType
import { DeleteManyInputType } from '@lib/type-graphql-query';
import { InputType } from '@lib/type-graphql';
import { ProductDTO } from './dto/product.dto';
@InputType()
export class DeleteManyProductsInput extends DeleteManyInputType(ProductDTO) {}

Schema:

input DeleteManyProductsInput {
filter: ProductFilter!
}

Input type for upsertOne mutations.

The UpsertOneInputType will generate an InputType that will require the user to provide an input record. If a record with the same unique identifier exists, it will be updated; otherwise, it will be created.

NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.

import { UpsertOneInputType } from '@lib/type-graphql-query';
import { InputType, Field } from '@lib/type-graphql';
import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')
export class ProductInputDTO {
@IsString()
@Field()
name!: string;
@IsBoolean()
@Field()
canBeSold!: boolean;
}
@InputType()
export class UpsertOneProductInput extends UpsertOneInputType('product', ProductInputDTO) {}

Schema:

input UpsertOneProductInput {
product: ProductInput!
}
input ProductInput {
name: String!
canBeSold: Boolean!
}

Input type for upsertMany mutations.

The UpsertManyInputType will generate an InputType that will require the user to provide an array of input records. Records with matching unique identifiers will be updated; others will be created.

NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.

import { UpsertManyInputType } from '@lib/type-graphql-query';
import { InputType, Field } from '@lib/type-graphql';
import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')
export class ProductInputDTO {
@IsString()
@Field()
name!: string;
@IsBoolean()
@Field()
canBeSold!: boolean;
}
@InputType()
export class UpsertManyProductsInput extends UpsertManyInputType('products', ProductInputDTO) {}

Schema:

input UpsertManyProductsInput {
products: [ProductInput!]!
}
input ProductInput {
name: String!
canBeSold: Boolean!
}

Type for handling localized fields in queries. See Translations for more information.

Type for handling localized fields in mutation inputs. See Translations for more information.

Wrapper type for mutation arguments that includes authorization context.

Args type for findById queries.

Args type for subscriptions.

Filter type for subscriptions.

Input type for setting a single relation.

Input type for setting multiple relations.

Args type for aggregate queries.

Response type for aggregate queries.

Here’s a complete example showing how to use types in a custom resolver:

import { Resolver, Query, Args, Mutation } from '@lib/type-graphql';
import {
QueryArgsType,
FilterType,
CreateOneInputType,
UpdateOneInputType,
DeleteOneInputType,
ProductDTO,
} from '@lib/type-graphql-query';
// Generate types
const ProductQueryArgs = QueryArgsType(ProductDTO);
const ProductFilter = FilterType(ProductDTO);
@Resolver(() => ProductDTO)
export class CustomProductResolver {
@Query(() => [ProductDTO])
async customQuery(
@Args(() => ProductQueryArgs) queryArgs: InstanceType<typeof ProductQueryArgs>,
): Promise<ProductDTO[]> {
// Use queryArgs.filter, queryArgs.paging, queryArgs.sorting
// ...
}
@Query(() => ProductDTO, { nullable: true })
async findById(@Args('id') id: string): Promise<ProductDTO | null> {
// ...
}
}
  1. Use Generated Types When Possible

    • Most types are automatically generated when using buildSchema or buildTypeDefsAndResolvers
    • Only create custom types when you need custom behavior
  2. Separate Input DTOs

    • Create separate DTOs for create/update operations
    • Don’t expose internal fields like createdAt, updatedAt in input types
  3. Reuse Types

    • Use QueryArgsType to get all related types (FilterType, SortType, etc.)
    • This ensures consistency across your API
  4. Type Safety

    • Always use TypeScript types when working with these classes
    • Use InstanceType<typeof TypeClass> to get the instance type
  • Queries - Learn about query endpoints
  • Mutations - Learn about mutation endpoints
  • Filtering - Understand filtering options
  • Sorting - Understand sorting options
  • Paging - Learn about pagination strategies
  • Resolvers - Learn about resolver implementation