Introduction
Developing an e-commerce platform requires seamless integration of various entities like users, products, orders, categories, and more. Using NestJS with TypeORM simplifies this process by providing a structured way to handle relationships and CRUD operations. In this guide, we will explore creating an e-commerce backend from scratch, covering all TypeORM relationships with PostgreSQL as our database.
Why Use TypeORM With NestJS?
- Object Relational Mapping: Simplifies database operations.
- Relations: Manage one-to-one, one-to-many, and many-to-many relationships efficiently.
- Declarative Approach: Use decorators to define entity behavior.
Prerequisites
Before starting, ensure you have the following installed:
- Node.js: For running the backend.
- NestJS CLI: For generating NestJS resources.
- PostgreSQL: As the relational database.
npm install -g @nestjs/cli
Setting Up NestJS and TypeORM
- Create a New Project:
nest new ecommerce-platform
- Install Dependencies:
npm install @nestjs/typeorm typeorm pg
-
Configure TypeORM:
Update
src/app.module.ts
:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'your-username',
password: 'your-password',
database: 'ecommerce',
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: true, // Avoid in production
}),
],
})
export class AppModule {}
Designing the Database Schema
For an e-commerce platform, the following entities are essential:
- User: Represents a customer or admin.
- Product: Represents items for sale.
- Category: Groups products.
- Order: Tracks purchases.
Creating Entities With TypeORM Relations
- User Entity:
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Order } from './order.entity';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column({ unique: true })
email: string;
@OneToMany(() => Order, (order) => order.user)
orders: Order[];
}
- Product Entity:
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm';
import { Category } from './category.entity';
@Entity()
export class Product {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column('decimal')
price: number;
@ManyToOne(() => Category, (category) => category.products)
category: Category;
}
- Category Entity:
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { Product } from './product.entity';
@Entity()
export class Category {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => Product, (product) => product.category)
products: Product[];
}
- Order Entity:
import { Entity, PrimaryGeneratedColumn, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
import { User } from './user.entity';
import { Product } from './product.entity';
@Entity()
export class Order {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne(() => User, (user) => user.orders)
user: User;
@ManyToMany(() => Product)
@JoinTable()
products: Product[];
}
Implementing CRUD Operations
- Generate Resources:
nest g resource users
nest g resource products
nest g resource categories
nest g resource orders
- User Service:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private userRepository: Repository<User>,
) {}
createUser(user: Partial<User>) {
return this.userRepository.save(user);
}
findAllUsers() {
return this.userRepository.find({ relations: ['orders'] });
}
findUserById(id: number) {
return this.userRepository.findOne({ where: { id }, relations: ['orders'] });
}
updateUser(id: number, updateUser: Partial<User>) {
return this.userRepository.update(id, updateUser);
}
deleteUser(id: number) {
return this.userRepository.delete(id);
}
}
Handling Relationships in CRUD Operations
Example: Create an Order With Products:
async createOrder(userId: number, productIds: number[]) {
const user = await this.userRepository.findOne({ where: { id: userId } });
const products = await this.productRepository.findByIds(productIds);
const order = new Order();
order.user = user;
order.products = products;
return this.orderRepository.save(order);
}
Example: Fetch Orders With User and Products:
async findOrders() {
return this.orderRepository.find({ relations: ['user', 'products'] });
}
Validating and Securing Your API
Use DTOs (Data Transfer Objects) with class-validator for validation:
npm install class-validator class-transformer
Example DTO:
import { IsNotEmpty, IsEmail } from 'class-validator';
export class CreateUserDto {
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
}
Controller:
@Post()
createUser(@Body() createUserDto: CreateUserDto) {
return this.userService.createUser(createUserDto);
}
Frequently Asked Questions
1. Why Use TypeORM for E-Commerce?
TypeORM simplifies working with relational databases, making it ideal for handling complex relationships in e-commerce platforms.
2. How Do I Avoid Circular Dependencies in Relations?
Use lazy relations or modularize your entities by grouping related ones into specific modules.
3. How Can I Improve Performance?
- Use pagination for large datasets.
- Use indexes on frequently queried columns.
Conclusion
By following this step-by-step guide, you have created an e-commerce backend using NestJS and TypeORM with PostgreSQL. This implementation supports CRUD operations for users, products, categories, and orders with all necessary relationships. Experiment further by adding features like authentication, inventory management, and reporting.
Top comments (0)