Steps to create your endpoint in Nest JS framework

Posted on October 03, 2025
Profile
Gastรณn Gaitan
October 03, 2025 ยท 1ย month ago
Steps to create your endpoint in Nest JS framework

Creating Endpoints in NestJS Microservices Architecture

Building scalable applications often requires breaking down monolithic structures into smaller, manageable microservices. In this guide, we'll explore how to create endpoints in a NestJS microservices architecture using an e-commerce platform example that handles product catalogs, user management, orders, and real-time inventory tracking.

Understanding the Architecture

This NestJS application follows a microservices pattern where each service handles specific business logic. The architecture includes an API Gateway that acts as a single entry point, with individual services for products, users, orders, inventory, payments, and notifications.

๐Ÿšช API Gateway 3000

Acts as the single entry point for all client requests. Routes requests to appropriate microservices and handles authentication, rate limiting, and request/response transformation.

๐Ÿ“ฆ Product Service 3001

Manages product catalogs, categories, pricing, and product information. Handles product search, filtering, and availability checks across the platform.

๐Ÿ‘ค User Service 3002

Handles user authentication, profiles, preferences, and account management. Integrates with social media login providers and manages user sessions.

๐Ÿ›’ Order Service 3003

Manages the complete order lifecycle from cart creation to fulfillment. Handles order states, shipping calculations, and order history tracking.

๐Ÿ“Š Inventory Service 3004

Tracks product stock levels in real-time, manages warehouse operations, and handles inventory reservations during the checkout process.

๐Ÿ’ณ Payment Service 3005

Processes payments securely through multiple payment gateways, handles refunds, and manages payment method storage with PCI compliance.

๐Ÿ“ง Notification Service 3006

Sends email notifications, push notifications, and SMS alerts for order updates, promotions, and account activities to customers.

File Structure Overview

The project follows a clear separation between shared libraries and individual microservices:

๐Ÿ“ ECommerce-API/
โ”‚
โ”œโ”€โ”€ ๐Ÿ“š libs/common/src/models/ โ† Shared entities & DTOs
โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฆ products/
โ”‚ โ”‚ โ”œโ”€โ”€ product.entity.ts
โ”‚ โ”‚ โ””โ”€โ”€ dto/
โ”‚ โ”‚ โ”œโ”€โ”€ create-product.dto.ts
โ”‚ โ”‚ โ””โ”€โ”€ update-product.dto.ts
โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€ ๐Ÿ‘ค users/
โ”‚ โ”‚ โ”œโ”€โ”€ user.entity.ts
โ”‚ โ”‚ โ””โ”€โ”€ dto/
โ”‚ โ”‚ โ”œโ”€โ”€ create-user.dto.ts
โ”‚ โ”‚ โ””โ”€โ”€ update-profile.dto.ts
โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€ ๐Ÿ›’ orders/
โ”‚ โ”‚ โ”œโ”€โ”€ order.entity.ts
โ”‚ โ”‚ โ””โ”€โ”€ dto/
โ”‚ โ”‚ โ”œโ”€โ”€ create-order.dto.ts
โ”‚ โ”‚ โ””โ”€โ”€ order-status.dto.ts
โ”‚ โ”‚
โ”‚ โ””โ”€โ”€ ๐Ÿ’ณ payments/
โ”‚ โ”œโ”€โ”€ payment.entity.ts
โ”‚ โ””โ”€โ”€ dto/
โ”‚ โ”œโ”€โ”€ payment-request.dto.ts
โ”‚ โ””โ”€โ”€ payment-response.dto.ts
โ”‚
โ””โ”€โ”€ ๐ŸŒ apps/ โ† Individual microservices
โ”‚
โ”œโ”€โ”€ ๐Ÿ‘ค user-service/src/
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ dto/ โ† Service-specific DTOs
โ”‚ โ”‚ โ”œโ”€โ”€ user-analytics.dto.ts
โ”‚ โ”‚ โ”œโ”€โ”€ login-response.dto.ts
โ”‚ โ”‚ โ”œโ”€โ”€ user-preferences.dto.ts
โ”‚ โ”‚ โ””โ”€โ”€ password-reset.dto.ts
โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€ ๐ŸŽฎ user-service.controller.ts โ† HTTP endpoints
โ”‚ โ”œโ”€โ”€ โš™๏ธ user-service.service.ts โ† Business logic
โ”‚ โ”œโ”€โ”€ ๐Ÿ—„๏ธ user-service.repository.ts โ† Data access
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฆ user-service.module.ts โ† NestJS module
โ”‚ โ””โ”€โ”€ ๐Ÿš€ main.ts โ† Bootstrap & Swagger
โ”‚
โ”œโ”€โ”€ ๐Ÿ“ฆ product-service/src/
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ dto/
โ”‚ โ”‚ โ”œโ”€โ”€ product-search.dto.ts
โ”‚ โ”‚ โ”œโ”€โ”€ category-filter.dto.ts
โ”‚ โ”‚ โ””โ”€โ”€ price-range.dto.ts
โ”‚ โ”‚
โ”‚ โ”œโ”€โ”€ ๐Ÿ“‹ product-service.controller.ts
โ”‚ โ”œโ”€โ”€ โš™๏ธ product-service.service.ts
โ”‚ โ”œโ”€โ”€ ๐Ÿ—„๏ธ product-service.repository.ts
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ฆ product-service.module.ts
โ”‚ โ””โ”€โ”€ ๐Ÿš€ main.ts
โ”‚
โ”œโ”€โ”€ ๐Ÿ›’ order-service/src/
โ”‚ โ”œโ”€โ”€ ๐Ÿ“ dto/
โ”‚ โ”‚ โ””โ”€โ”€ checkout-request.dto.ts
โ”‚ โ”‚
โ”‚ โ””โ”€โ”€ ... (similar structure)
โ”‚
โ”œโ”€โ”€ ๐Ÿ“Š inventory-service/src/
โ”œโ”€โ”€ ๐Ÿ’ณ payment-service/src/
โ”œโ”€โ”€ ๐Ÿ“ง notification-service/src/
โ””โ”€โ”€ ๐Ÿšช api-gateway/src/

Step-by-Step Endpoint Creation

Let's create a practical example: a User Analytics endpoint that returns performance metrics and activity data for users.

Step 1: Plan Your Endpoint

๐ŸŽฏ Goal: Create GET /users/:id/analytics

First, determine which microservice should handle this endpoint. Since we're dealing with user analytics, this belongs in the user-service.

Step 2: Create the Response DTO

DTOs (Data Transfer Objects) define the structure of data flowing in and out of your endpoints. For service-specific DTOs, create them in the service's dto folder:

// apps/user-service/src/dto/user-analytics-response.dto.ts import { ApiProperty } from '@nestjs/swagger'; export class UserAnalyticsResponseDto { @ApiProperty({ description: 'Total number of orders placed by user', example: 28 }) totalOrders: number; @ApiProperty({ description: 'Total amount spent by user', example: 1485.50 }) totalSpent: number; @ApiProperty({ description: 'Average order value', example: 53.05 }) averageOrderValue: number; @ApiProperty({ description: 'Last login timestamp', example: '2024-01-15T10:30:00Z' }) lastLoginDate: Date; @ApiProperty({ description: 'Favorite product category', example: 'Electronics' }) favoriteCategory: string; }

Step 3: Implement Repository Logic

The repository layer handles database interactions. Add a method to fetch user analytics:

// In user-service.repository.ts async getUserAnalytics(userId: number): Promise<UserAnalyticsResponseDto> { const query = ` SELECT COUNT(o.id) as total_orders, COALESCE(SUM(o.total_amount), 0) as total_spent, COALESCE(AVG(o.total_amount), 0) as average_order_value, u.last_login_date, ( SELECT c.name FROM categories c JOIN products p ON p.category_id = c.id JOIN order_items oi ON oi.product_id = p.id JOIN orders o2 ON o2.id = oi.order_id WHERE o2.user_id = $1 GROUP BY c.name ORDER BY COUNT(*) DESC LIMIT 1 ) as favorite_category FROM users u LEFT JOIN orders o ON o.user_id = u.id WHERE u.id = $1 GROUP BY u.id, u.last_login_date `; const result = await this.databaseService.query(query, [userId]); return result[0]; }

Step 4: Add Business Logic in Service

The service layer processes the repository data and applies business rules:

// In user-service.service.ts async getUserAnalytics(userId: number): Promise<UserAnalyticsResponseDto> { const user = await this.userRepository.findOne(userId); if (!user) { throw new NotFoundException( `User with ID ${userId} not found` ); } const analytics = await this.userRepository.getUserAnalytics(userId); // Apply business logic and data formatting return { totalOrders: analytics.total_orders || 0, totalSpent: Number( (analytics.total_spent || 0).toFixed(2) ), averageOrderValue: Number( (analytics.average_order_value || 0).toFixed(2) ), lastLoginDate: analytics.last_login_date, favoriteCategory: analytics.favorite_category || 'No purchases yet' }; }

Step 5: Create the Controller Endpoint

Controllers define the HTTP endpoints and handle request/response logic:

// In user-service.controller.ts @Get(':id/analytics') @ApiOperation({ summary: 'Get user analytics and activity metrics' }) @ApiResponse({ status: 200, description: 'User analytics retrieved successfully', type: UserAnalyticsResponseDto, }) @ApiResponse({ status: 404, description: 'User not found', }) async getUserAnalytics( @Param('id') id: string ): Promise<UserAnalyticsResponseDto> { return await this.userService.getUserAnalytics(+id); }

Step 6: Register Dependencies

Ensure all dependencies are properly registered in the module (usually already configured):

// user-service.module.ts @Module({ imports: [ ConfigModule.forRoot(), DatabaseModule, DatabaseModule.forFeature([ User, Order, Product ]), ], controllers: [UserServiceController], providers: [ UserServiceService, UserServiceRepository ], }) export class UserServiceModule {}

Request Flow Visualization

Understanding how a request flows through the system helps in debugging and optimization:

๐ŸŒ Client Request: GET /users/456/analytics
โ†“
๐Ÿšช API Gateway (port 3000)
Routes & authenticates request
โ†“
๐Ÿ‘ค User Service (port 3002)
Receives the request
โ†“
๐ŸŽฎ Controller
Validates parameters & routes request
โ†“
โš™๏ธ Service Layer
Applies business logic & validation
โ†“
๐Ÿ—„๏ธ Repository Layer
Queries PostgreSQL database
โ†“
๐Ÿ“Š Response Generated:
{ totalOrders: 28, totalSpent: 1485.50, ... }
โ†“
๐ŸŒ Client receives JSON response

Testing Your Endpoint

Each microservice automatically generates Swagger documentation for easy testing:

๐Ÿงช Testing Options:

  • Swagger UI: http://localhost:3002/api
  • Direct HTTP: http://localhost:3002/users/456/analytics
  • Postman/Insomnia: For comprehensive API testing
  • Unit Tests: Jest framework for automated testing

DTO Best Practices

The application uses two types of DTOs strategically:

๐Ÿ“ DTO Organization Rules:

  • libs/common/src/models/: DTOs shared across multiple services
  • apps/[service]/src/dto/: Service-specific DTOs
  • Validation: Use class-validator decorators for automatic validation
  • Documentation: Always include @ApiProperty for Swagger docs

Advanced Features

Automatic Documentation

The framework automatically generates comprehensive API documentation using Swagger. Each service exposes its documentation at `/api` and machine-readable specs at `/api-json`.

Real-time Capabilities

Services can implement WebSockets for real-time updates, such as live inventory changes or order status notifications to connected clients.

Event-Driven Architecture

The system uses message queues (Redis/RabbitMQ) for inter-service communication, allowing services to react to events like `OrderPlaced` or `PaymentProcessed`.

Conclusion

Creating endpoints in this NestJS microservices architecture follows a clear, structured approach. The separation of concerns between DTOs, services, repositories, and controllers makes the codebase maintainable and scalable. With automatic documentation, validation, and error handling, developers can focus on business logic while the framework handles the infrastructure concerns.

This architecture pattern is ideal for e-commerce platforms, SaaS applications, and any system that requires independent scaling of different business domains.