nestjs-query
- DRY – querying, sorting and paging is handled by this lib.
- Easier time with CRUD operations in GraphQL.
- No n+1 problem.
- “Connections” compliant pagination schema.
nestjs-query + TypeORM + NestJS + PostgreSQL
-
pnpm add @ptc-org/nestjs-query-core @ptc-org/nestjs-query-graphql @ptc-org/nestjs-query-typeorm @nestjs/typeorm @nestjs/common @nestjs/graphql @nestjs/apollo @nestjs/config @apollo/server graphql graphql-subscriptions class-transformer class-validator dataloader typeorm pg -
cd typeorm/apps/borprobe-nest nest g resource alert-type nest g resource alert ```ExpressJS -
Open your
*.entity.tsand modify it to use TypeORM and acts as youObjecttype.[!TIP]
It’s always easy to merge your Custom Object Type defined for GraphQL with your persistence layer (in our case the entity we need for TypeORM). But it is no that easy to decouple them. But since here I am experimenting I will merge them from the get go. But you might wanna think twice before jumping into coding in a real world project.
- For create we can use the one generated by
@ptc-org/nestjs-query-graphqlbut it will have things likeid,createdAt, andupdatedAtwhich ain’t required. So let’s modifydto/*.input.tsto reflect our desired DTO. - Configure your NestJS app as it is described here.
- Config your TypeORM according to NestJS doc.
-
Config your
NestjsQueryGraphQLModulefor each module:import { Module } from "@nestjs/common"; import { NestjsQueryGraphQLModule } from "@ptc-org/nestjs-query-graphql"; import { NestjsQueryTypeOrmModule } from "@ptc-org/nestjs-query-typeorm"; import { AlertTypeResolver } from "./alert-type.resolver"; import { AlertTypeService } from "./alert-type.service"; import { CreateAlertTypeInput } from "./dto/create-alert-type.input"; import { AlertType } from "./entities/alert-type.entity"; @Module({ imports: [ NestjsQueryGraphQLModule.forFeature({ imports: [NestjsQueryTypeOrmModule.forFeature([AlertType])], resolvers: [ { EntityClass: AlertType, DTOClass: AlertType, CreateDTOClass: CreateAlertTypeInput, }, ], }), ], providers: [AlertTypeResolver, AlertTypeService], }) export class AlertTypeModule {}[!NOTE]
No need for
TypeOrmModule.forFeature([AlertType]),sinceNestjsQueryTypeOrmModulewill register your entity with TypeORM. - Then we need to take care of
AppModule, import and config:ConfigModule.TypeOrmModule.GraphQLModule.AlertModule.AlertTypeModule.
-
Generate migration for TypeORM:
nx migration:gen botprobe-nest --name init -
Run the generated migrations:
nx migration:run botprobe-nest
[!TIP]
Create new empty migration with:
nx migration:create botprobe-nest --name init
BTW I have written a post for migration in TypeORM in dev.to here.
Extracting User ID off of the Decoded JWT Token
-
Create
AuthModule:nest g module auth nest g service auth nest g guard auth nest g decorator auth- Rename the newly created decorator to
get-user.decorator.tsand move it to adecoratorsdirectory. - Rename the guard to
jwt-auth.guard.tsand move it to aguardsfolder. - Same for service, rename it to
auth.service.tsand move it toservicesdirectory. - Create a new directory called
strategiesand inside it create a file calledjwt.strategy.ts.
- Rename the newly created decorator to
-
We need to config JWT and Auth module. thus we’re gonna create configs:
auth.config.ts.jwt-module.config.ts.
-
Add the guard globally to a module if you need to protect the every resolver in that module:
@Module({ imports: [ NestjsQueryGraphQLModule.forFeature({ resolvers: [ { + guards: [GraphqlJwtAuthGuard], }, ], }), ], }) export class AlertModule {} -
Create a new hook
apps/botprobe-nest/src/alert/hooks/before-create-alert.hook.ts:https://github.com/kasir-barati/nestjs-materials/blob/main/typeorm/apps/botprobe-nest/src/alert/hooks/before-create-alert.hook.ts
This hook will be executed before the request reaching resolver. Thus we can inside it easily access context and extract user ID from it, and finally attach it to the
input.
[!NOTE]
I’ve added a dummy login endpoint as well (resolver), it does not do anything. You’ll get an
accessTokenwhenever you call it. I added it for the sake of my e2e tests :slightly_smiling_face:.
Request Flow from Auth to Resolver

Writing E2E Tests – Generating an SDK with genql
-
npm i -g @genql/cli - Add a new script to your
apps/botprobe-nest-e2e, and do not forget that you need to re-execute this script after each change you make to you API:{ "targets": { "genql-client": { "executor": "nx:run-commands", "options": { "commands": [ { "command": "[ -d './__generated__' ] && rm -rf ./__generated__", "forwardAllArgs": false }, { "command": "genql --endpoint http://localhost:4000/graphql --output ./__generated__", "forwardAllArgs": false } ], "cwd": "{projectRoot}" } } } } - And then you can use it like this:
import { Client, createClient } from "../../__generated__"; const client = createClient(); client.query({ alerts: { /*...*/ }, });