In the previous article, we learned about the Schema First Approach for setting up GraphQL with NestJS. Now, we will explore the Code First Approach.
In the Code First Approach, we define our GraphQL types and resolvers directly in TypeScript code instead of writing separate GraphQL schema files. This approach leverages the power of TypeScript and its type system to ensure consistency and type safety throughout our application.
Step 1: Remove the GraphQL Schema File
First, let's remove the book.schema.graphql
file that we created in the previous approach, as we won't be needing it anymore.
Step 2: Modify the app.module.ts
Next, we need to update the app.module.ts
file to configure the Code First Approach. Here's the updated code:
import { ApolloDriverConfig, ApolloDriver } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { BookResolver } from './book/book.resolver';
import { join } from 'path';
@Module({
imports: [
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
playground: true, // Set to false in production
autoSchemaFile: join(process.cwd(), 'src/schema.graphql'), // Automatically generate the GraphQL schema
// ts-morph
definitions: {
path: join(process.cwd(), 'src/graphql.ts'), // Path to the generated file with TypeScript definitions
},
}),
BookResolver,
],
controllers: [],
providers: [],
})
export class AppModule {}
In this updated code, we've added two new properties to the GraphQLModule.forRoot
configuration:
autoSchemaFile
: This property specifies the path where the automatically generated GraphQL schema file will be saved. In this case, it's set tosrc/schema.graphql
.definitions
: This property is specific to thets-morph
library, which is used to generate TypeScript definitions from the GraphQL schema. Thepath
property insidedefinitions
specifies the location where the TypeScript definitions will be saved. In this case, it's set tosrc/graphql.ts
.
Step 3: Install ts-morph
To use the Code First Approach, we need to install the ts-morph
library, which is responsible for generating TypeScript definitions from the GraphQL schema. Run the following command to install ts-morph
:
npm install ts-morph
Step 4: Define the GraphQL Types and Resolvers
Now, let's create the book.resolver.ts
file in the book
folder, where we'll define our GraphQL types and resolvers.
import { Query, Resolver } from '@nestjs/graphql';
import { Book } from './book.schema';
import { Book as BookModel } from '../graphql';
@Resolver(() => Book)
export class BookResolver {
@Query(() => [Book], { name: 'books' }) // name set instead of getAllBooks it's now books
getAllBooks() {
const arr: BookModel[] = [
{
id: 1,
title: 'Book 1',
price: 10,
},
{
id: 2,
title: 'Book 2',
price: 20,
},
{
id: 3,
title: 'Book 3',
price: 30,
},
];
return arr;
}
}
In this file, we've defined a Book
type and a books
query resolver using the @Resolver
and @Query
decorators from @nestjs/graphql
.
The Book
type is imported from the book.schema.ts
file, which we'll create shortly. The BookModel
type is imported from the graphql.ts
file, which will be automatically generated by the ts-morph
library based on our GraphQL schema.
Step 5: Define the GraphQL Object Types
Next, we need to create the book.schema.ts
file in the book
folder, where we'll define our GraphQL object types.
import { ObjectType, Field, Int, ID } from '@nestjs/graphql';
@ObjectType()
export class Book {
@Field(() => ID)
id: number;
@Field()
title: string;
@Field(() => Int)
price: number;
}
In this file, we've defined the Book
object type using the @ObjectType
decorator from @nestjs/graphql
. Each field of the Book
type is defined using the @Field
decorator, along with the appropriate type decorator (ID
for the id
field, and Int
for the price
field).
Step 6: Start the NestJS Server
Now, we can start the NestJS server by running the following command:
npm run start:dev
or
yarn start:dev
When you start the server, it will automatically generate the schema.graphql
file in the src
directory and the graphql.ts
file with the TypeScript definitions. The graphql.ts
file can be imported and used in other parts of your application to ensure type safety when working with GraphQL types.
You can then navigate to http://localhost:3000/graphql
and access the GraphQL Playground to test your queries and mutations.
In this blog post, we learned how to set up GraphQL with NestJS using the Code First Approach. This approach allows us to define our GraphQL types and resolvers directly in TypeScript code, leveraging the power of TypeScript's type system for better type safety and consistency.
The Code First Approach has a few advantages over the Schema First Approach:
Type Safety: By defining our types in TypeScript, we get better type safety and can catch errors during development time, rather than at runtime.
Colocation: With the Code First Approach, we can colocate our types, resolvers, and other related code, making it easier to maintain and understand the codebase.
IDE Support: Most modern IDEs provide better tooling and code completion for TypeScript code, making it easier to work with GraphQL types and resolvers.
However, the Schema First Approach can still be preferred in certain scenarios, such as when working with an existing GraphQL API or when the schema is more stable and needs to be shared across different platforms or languages.
Overall, both approaches have their advantages and trade-offs, and the choice between them often depends on the specific requirements and preferences of the project and team.