typescript 57 lines · 7 steps

Building a CRUD service in NestJS

A NestJS provider wraps a TypeORM repository to create, read, update, and delete users while guarding against duplicates and missing rows.

Explained by highlit
1import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
2import { InjectRepository } from '@nestjs/typeorm';
3import { Repository, DeepPartial } from 'typeorm';
4import { User } from './entities/user.entity';
5import { CreateUserDto } from './dto/create-user.dto';
6import { UpdateUserDto } from './dto/update-user.dto';
7 
8@Injectable()
9export class UsersService {
10 constructor(
11 @InjectRepository(User)
12 private readonly usersRepository: Repository<User>,
13 ) {}
14 
15 async create(dto: CreateUserDto): Promise<User> {
16 const existing = await this.usersRepository.findOne({
17 where: { email: dto.email },
18 });
19 
20 if (existing) {
21 throw new ConflictException(`Email ${dto.email} is already registered`);
22 }
23 
24 const user = this.usersRepository.create(dto as DeepPartial<User>);
25 return this.usersRepository.save(user);
26 }
27 
28 findAll(): Promise<User[]> {
29 return this.usersRepository.find({
30 order: { createdAt: 'DESC' },
31 });
32 }
33 
34 async findOne(id: string): Promise<User> {
35 const user = await this.usersRepository.findOne({ where: { id } });
36 
37 if (!user) {
38 throw new NotFoundException(`User ${id} not found`);
39 }
40 
41 return user;
42 }
43 
44 async update(id: string, dto: UpdateUserDto): Promise<User> {
45 const user = await this.findOne(id);
46 Object.assign(user, dto);
47 return this.usersRepository.save(user);
48 }
49 
50 async remove(id: string): Promise<void> {
51 const result = await this.usersRepository.delete(id);
52 
53 if (result.affected === 0) {
54 throw new NotFoundException(`User ${id} not found`);
55 }
56 }
57}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Injecting a repository keeps data access declarative and testable while the service focuses on business rules.
  2. 2Translating data conditions into NestJS HTTP exceptions gives callers meaningful status codes for free.
  3. 3Reusing findOne inside update centralizes the not-found check so every read path enforces the same guarantee.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a CRUD service in NestJS — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code