What if your API schema updated itself every time you changed your code?
Why Code-first approach in NestJS? - Purpose & Use Cases
Imagine building an API where you first write a separate schema file, then manually keep your code and schema in sync.
Every time you add a new feature, you must update multiple places by hand.
This manual syncing is slow and error-prone.
You might forget to update the schema or code, causing bugs and confusion.
It feels like juggling too many balls at once.
The code-first approach lets you define your API schema directly in your code using decorators and types.
This means your code and schema are always in sync automatically.
It reduces mistakes and speeds up development.
Define schema in separate files Update schema and code separately Keep them in sync manually
@ObjectType() class User { @Field() name: string; } // Schema generated from code
You can build APIs faster and with fewer errors because your code is the single source of truth.
When creating a user management API, you write your user model once in code, and the GraphQL schema updates automatically.
Manual schema syncing is slow and risky.
Code-first approach keeps schema and code together.
It makes API development faster and safer.
Practice
Solution
Step 1: Understand code-first approach basics
The code-first approach means you write your GraphQL types and resolvers directly in TypeScript code using classes and decorators.Step 2: Compare with other approaches
Unlike schema-first, you do not write schema files manually; instead, the schema is generated automatically from your code.Final Answer:
Writing TypeScript classes and decorators to define GraphQL schema -> Option CQuick Check:
Code-first = Define schema in code [OK]
- Confusing code-first with schema-first approach
- Thinking schema files must be manually written
- Assuming REST is involved in code-first GraphQL
Solution
Step 1: Identify decorator for GraphQL object type
In code-first, @ObjectType() marks a class as a GraphQL object type to generate schema.Step 2: Differentiate from other decorators
@Resolver() marks resolver classes, @Query() marks query methods, and @Injectable() is for dependency injection, not schema types.Final Answer:
@ObjectType() -> Option AQuick Check:
@ObjectType = GraphQL type class [OK]
- Using @Resolver() instead of @ObjectType() for types
- Confusing @Query() with type decorators
- Thinking @Injectable() defines GraphQL schema
hello()?
import { Query, Resolver } from '@nestjs/graphql';
@Resolver()
export class HelloResolver {
@Query(() => String)
hello() {
return 'Hello, NestJS!';
}
}Solution
Step 1: Analyze the resolver method
The method hello() returns the string 'Hello, NestJS!'. The @Query decorator specifies the return type as String.Step 2: Understand GraphQL query result
When queried, the hello field returns the string value wrapped in quotes as a valid GraphQL string response.Final Answer:
"Hello, NestJS!" -> Option AQuick Check:
hello() returns string 'Hello, NestJS!' [OK]
- Expecting null or undefined instead of returned string
- Thinking missing return type causes runtime error
- Confusing resolver method with schema definition
import { Query, Resolver } from '@nestjs/graphql';
@Resolver()
export class SampleResolver {
@Query()
sample() {
return 123;
}
}Solution
Step 1: Check @Query decorator usage
The @Query decorator requires a return type function, e.g., @Query(() => Int) or @Query(() => String).Step 2: Identify missing return type
Here, @Query() is missing the return type, which causes schema generation errors.Final Answer:
Missing return type in @Query decorator -> Option BQuick Check:
@Query needs return type function [OK]
- Omitting return type in @Query decorator
- Adding @ObjectType to resolver class incorrectly
- Assuming async is mandatory for resolver methods
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class User {
@Field(() => String, { nullable: true })
nickname?: string;
}
What does this code do?Solution
Step 1: Understand @Field decorator options
The @Field decorator with { nullable: true } marks the field as nullable in GraphQL schema, allowing null values.Step 2: Check TypeScript optional property
Using ? in nickname?: string means the property is optional in TypeScript, matching nullable in GraphQL.Step 3: Confirm schema generation behavior
This combination correctly generates a GraphQL field that can be omitted or set to null without errors.Final Answer:
Defines a User type with an optional nullable nickname field in GraphQL schema -> Option DQuick Check:
nullable + optional = optional nullable field [OK]
- Omitting nullable option for optional fields
- Confusing optional in TypeScript with required in GraphQL
- Expecting errors for optional nullable fields
Ready to prove it?
Pass the test and this pattern moves unknown
