
Nestjs with Graphql
- Atul
- Programming
- December 14, 2024
Table of Contents
Harnessing the power of TypeScript & GraphQL
GraphQL is a powerful query language for APIs and a runtime for fulfilling those queries with your existing data. It’s an elegant approach that solves many problems typically found with REST APIs. For background, we suggest reading this comparison between GraphQL and REST. GraphQL combined with TypeScript helps you develop better type safety with your GraphQL queries, giving you end-to-end typing.
Creating new project:
nest new hello-graphql
⚡ We will scaffold your app in a few seconds..
? Which package manager would you ❤️ to use? yarn
CREATE hello-graphql/.eslintrc.js (663 bytes)
CREATE hello-graphql/.prettierrc (51 bytes)
CREATE hello-graphql/README.md (5213 bytes)
CREATE hello-graphql/nest-cli.json (171 bytes)
CREATE hello-graphql/package.json (1949 bytes)
CREATE hello-graphql/tsconfig.build.json (97 bytes)
CREATE hello-graphql/tsconfig.json (546 bytes)
CREATE hello-graphql/src/app.controller.ts (274 bytes)
CREATE hello-graphql/src/app.module.ts (249 bytes)
CREATE hello-graphql/src/app.service.ts (142 bytes)
CREATE hello-graphql/src/main.ts (228 bytes)
CREATE hello-graphql/src/app.controller.spec.ts (617 bytes)
CREATE hello-graphql/test/jest-e2e.json (183 bytes)
CREATE hello-graphql/test/app.e2e-spec.ts (630 bytes)
✔ Installation in progress... ☕
🚀 Successfully created project hello-graphql
👉 Get started with the following commands:
$ cd hello-graphql
$ yarn run start
Thanks for installing Nest 🙏
Please consider donating to our open collective
to help us maintain this package.
🍷 Donate: https://opencollective.com/nest
Then start the server:
yarn run start:dev
Found 0 errors. Watching for file changes.
This should be there in your terminal output.
Testing with API Client:
Open Bruno
GET @ http://localhost:3000 should show Hello World.
Adding dependencies:
# For Express and Apollo (default)
npm i @nestjs/graphql @nestjs/apollo @apollo/server graphql
Overview#
Nest offers two ways of building GraphQL applications, the
code first
and theschema first
methods. You should choose the one that works best for you. Most of the chapters in this GraphQL section are divided into two main parts: one you should follow if you adopt code first, and the other to be used if you adopt schema first.In the code first approach, you use decorators and TypeScript classes to generate the corresponding GraphQL schema. This approach is useful if you prefer to work exclusively with TypeScript and avoid context switching between language syntaxes.
In the schema first approach, the source of truth is GraphQL SDL (Schema Definition Language) files. SDL is a language-agnostic way to share schema files between different platforms. Nest automatically generates your TypeScript definitions (using either classes or interfaces) based on the GraphQL schemas to reduce the need to write redundant boilerplate code.
Adding GraphQL module to project:
import { Module } from "@nestjs/common";
import { GraphQLModule } from "@nestjs/graphql";
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
}),
],
})
export class AppModule {}
This gives error in console:
throw new Error(errors.map((error) => error.message).join('\n\n'));
^
Error: Query root type must be provided.
at assertValidSchema (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/graphql/type/validate.js:59:11)
at Function.generateSchemaDerivedData (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@apollo/server/src/ApolloServer.ts:734:22)
at Object.schemaDerivedDataProvider (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@apollo/server/src/ApolloServer.ts:276:28)
at SchemaManager (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@apollo/server/src/utils/schemaManager.ts:79:36)
at ApolloServer (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@apollo/server/src/ApolloServer.ts:273:26)
at ApolloDriver.registerExpress (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@nestjs/apollo/dist/drivers/apollo-base.driver.js:85:24)
at ApolloDriver.registerServer (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@nestjs/apollo/dist/drivers/apollo.driver.js:36:24)
at ApolloDriver.start (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@nestjs/apollo/dist/drivers/apollo.driver.js:21:20)
at GraphQLModule.onModuleInit (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@nestjs/graphql/dist/graphql.module.js:123:36)
at async callModuleInitHook (/Desktop/Projects/Learning_Nestjs/GraphQL/hello-graphql/node_modules/@nestjs/core/hooks/on-module-init.hook.js:51:9)
Node.js v20.11.1
This blog post from NestJS does not seems to be showing good results. But I have a repository link for code first approach. Let’s go through that.
New setup!
Download this project here.
Install all the dependancies and run the server.
Visit http://localhost:3000/graphql
A cool thing pops up!
This is docs section, API documentation sort of.
This is schema of the current project.
LOL! I have no clue what to write here.
In recipes.service.ts file
private recipes: Recipe[] = [
{
id: "1",
title: "Grilled Chicken",
description: "Delicious grilled chicken with herbs and spices",
creationDate: new Date(),
ingredients: ["chicken", "olive oil", "salt", "pepper"],
},
{
id: "2",
title: "Vegetable Stir-Fry",
description: "Healthy stir-fried vegetables with a flavorful sauce",
creationDate: new Date(),
ingredients: [
"broccoli",
"carrots",
"bell peppers",
"soy sauce",
"garlic",
],
},
// Add more recipes as needed
];
Add this private variable.
Then in GraphQL playground:
query {
recipes {
description
ingredients
}
}
Enter this and you will get the data back!!
Adding new resource to Nest
nest g resource
? What name would you like to use for this resource (plural, e.g., "users")? companies
? What transport layer do you use? GraphQL (code first)
? Would you like to generate CRUD entry points? Yes
CREATE src/companies/companies.module.ts (253 bytes)
CREATE src/companies/companies.resolver.spec.ts (565 bytes)
CREATE src/companies/companies.resolver.ts (1228 bytes)
CREATE src/companies/companies.service.spec.ts (481 bytes)
CREATE src/companies/companies.service.ts (669 bytes)
CREATE src/companies/dto/create-company.input.ts (199 bytes)
CREATE src/companies/dto/update-company.input.ts (255 bytes)
CREATE src/companies/entities/company.entity.ts (190 bytes)
UPDATE src/app.module.ts (1040 bytes)
This will add the new module at AppModule
@Module({
imports: [
RecipesModule,
UsersModule,
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: "schema.gql",
transformSchema: (schema) => upperDirectiveTransformer(schema, "upper"),
installSubscriptionHandlers: true,
buildSchemaOptions: {
directives: [
new GraphQLDirective({
name: "upper",
locations: [DirectiveLocation.FIELD_DEFINITION],
}),
],
},
}),
CompaniesModule,
],
})
export class AppModule {}
Remember GraphQL has a Resolver not a Controller, so there will be a file called companies.resolver.ts
import { Resolver, Query, Mutation, Args, Int } from "@nestjs/graphql";
import { CompaniesService } from "./companies.service";
import { Company } from "./entities/company.entity";
import { CreateCompanyInput } from "./dto/create-company.input";
import { UpdateCompanyInput } from "./dto/update-company.input";
@Resolver(() => Company)
export class CompaniesResolver {
constructor(private readonly companiesService: CompaniesService) {}
@Mutation(() => Company)
createCompany(
@Args("createCompanyInput") createCompanyInput: CreateCompanyInput
) {
return this.companiesService.create(createCompanyInput);
}
@Query(() => [Company], { name: "companies" })
findAll() {
return this.companiesService.findAll();
}
@Query(() => Company, { name: "company" })
findOne(@Args("id", { type: () => Int }) id: number) {
return this.companiesService.findOne(id);
}
@Mutation(() => Company)
updateCompany(
@Args("updateCompanyInput") updateCompanyInput: UpdateCompanyInput
) {
return this.companiesService.update(
updateCompanyInput.id,
updateCompanyInput
);
}
@Mutation(() => Company)
removeCompany(@Args("id", { type: () => Int }) id: number) {
return this.companiesService.remove(id);
}
}
After running the server the resource is added to the GraphQL schema.
That resource is available at the playground.