Implementing CRUD operations in a GraphQL API using Nest.js involves setting up mutations and queries that correspond to create, read, update, and delete actions. Below, I'll outline how to implement these CRUD operations using a simplified example with a Recipe
entity.
1. Setup the GraphQL Module
Assuming you have already set up your Nest.js project with GraphQL as outlined in the previous response, ensure your GraphQL module is configured correctly in app.module.ts
.
2. Define the GraphQL Types
Using the code-first approach, define your entity as a GraphQL type. Here’s the Recipe
class:
import { ObjectType, Field, ID } from '@nestjs/graphql';
@ObjectType()
export class Recipe {
@Field(() => ID)
id: string;
@Field()
title: string;
@Field({ nullable: true })
description?: string;
}
3. Create Input Types
For mutations, you will need input types. Here's how you can define them for creating and updating recipes:
import { InputType, Field } from '@nestjs/graphql';
@InputType()
export class CreateRecipeInput {
@Field()
title: string;
@Field({ nullable: true })
description?: string;
}
@InputType()
export class UpdateRecipeInput {
@Field(() => ID)
id: string;
@Field({ nullable: true })
title?: string;
@Field({ nullable: true })
description?: string;
}
4. Define Resolvers
Create a resolver for handling queries and mutations:
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { Recipe } from './entities/recipe.entity';
import { CreateRecipeInput, UpdateRecipeInput } from './dto/recipe.input';
@Resolver(of => Recipe)
export class RecipeResolver {
private recipes: Recipe[] = []; // This will act as our in-memory database
@Query(returns => Recipe, { nullable: true })
async recipe(@Args('id', { type: () => ID }) id: string): Promise<Recipe> {
return this.recipes.find(recipe => recipe.id === id);
}
@Query(returns => [Recipe])
async recipes(): Promise<Recipe[]> {
return this.recipes;
}
@Mutation(returns => Recipe)
async createRecipe(@Args('createRecipeData') createRecipeData: CreateRecipeInput): Promise<Recipe> {
const recipe = {
id: Math.random().toString(), // generate a random ID for example purposes
...createRecipeData,
};
this.recipes.push(recipe);
return recipe;
}
@Mutation(returns => Recipe)
async updateRecipe(@Args('updateRecipeData') updateRecipeData: UpdateRecipeInput): Promise<Recipe> {
const recipe = this.recipes.find(r => r.id === updateRecipeData.id);
if (!recipe) {
throw new Error('Recipe not found');
}
Object.assign(recipe, updateRecipeData);
return recipe;
}
@Mutation(returns => Boolean)
async deleteRecipe(@Args('id', { type: () => ID }) id: string): Promise<boolean> {
const index = this.recipes.findIndex(recipe => recipe.id === id);
if (index === -1) {
throw new Error('Recipe not found');
}
this.recipes.splice(index, 1);
return true;
}
}
5. Connect to a Real Database
In a real application, you should replace the in-memory array with a database. You can integrate with a database like PostgreSQL using TypeORM or any other database module. Use repositories or custom services to handle data operations.
6. Considerations for Production
- Validation: Add DTO validation using class-validator to ensure data integrity.
- Authorization: Secure your API using guards and decorators to manage who can perform CRUD operations.
- Error Handling: Implement proper error handling to manage and respond to errors gracefully.
- Testing: Write unit and integration tests for your resolvers and services to ensure they work as expected.
This example demonstrates basic CRUD operations using Nest.js and GraphQL. The code-first approach allows you to maintain your GraphQL schema in TypeScript, making it easy to refactor and understand.
If you enjoy my content and would like to support my work, you can buy me a coffee. Your support is greatly appreciated!
Disclaimer: This content is generated by AI.
Top comments (0)