seven365-http-foundation
v0.0.7
Published
Clean Architecture utilities for Express: Type-safe DTOs, standardized service returns, and MongoDB-friendly request helpers.
Maintainers
Readme
seven365-http-foundation
Clean Architecture utilities for Express: Type-safe DTOs, standardized service returns, and MongoDB-friendly request helpers.
Installation
npm install seven365-http-foundationIdeal Folder Structure
To maintain a clean Service-Repository pattern in your Node.js backend, we recommend the following structure:
src/
├── controllers/ # Express Controllers: Handle HTTP logic & use ResponseHelper
├── services/ # Business Logic: Use Repositories & return ServiceResponse
├── repositories/ # Data Access: Interaction with MongoDB/Mongoose
├── models/ # Database Schemas: Mongoose Models/Entities
├── requests/ # Request Validation: Extends BaseRequest with Joi Schemas
├── dtos/ # Data Transfer: Extends BaseDto for structured data
├── middleware/ # Custom Middleware: Validation, Auth, etc.
└── index.ts # Entry pointComplete Usage Flow
1. The Model (Entity)
import { Schema, model } from 'mongoose';
const UserSchema = new Schema({
email: { type: String, required: true, unique: true },
username: { type: String, required: true },
isActive: { type: Boolean, default: true }
}, { timestamps: true });
export const UserModel = model('User', UserSchema);2. The Request & DTO
import { BaseRequest } from 'seven365-http-foundation';
import Joi from 'joi';
// Joi Schema for Middleware validation
export const CreateUserSchema = Joi.object({
email: Joi.string().email().required(),
username: Joi.string().min(3).required(),
});
// Request Class
export class CreateUserRequest extends BaseRequest {
public toDto() {
return {
email: this.getString('email'),
username: this.getString('username')
};
}
}3. The Repository
import { UserModel } from '../models/UserModel';
export class UserRepository {
async findByEmail(email: string) {
return await UserModel.findOne({ email });
}
async create(data: any) {
return await UserModel.create(data);
}
}4. The Service
import { ServiceResponse } from 'seven365-http-foundation';
import { UserRepository } from '../repositories/UserRepository';
export class UserService {
private userRepository = new UserRepository();
async registerUser(dto: any): Promise<ServiceResponse> {
const existingUser = await this.userRepository.findByEmail(dto.email);
if (existingUser) {
return ServiceResponse.error('User already exists');
}
const newUser = await this.userRepository.create(dto);
return ServiceResponse.success('Registration successful', newUser);
}
}5. The Controller
import { Request, Response } from 'express';
import { CreateUserRequest } from '../requests/CreateUserRequest';
import { UserService } from '../services/UserService';
import { ResponseHelper, HttpResponse } from 'seven365-http-foundation';
export class UserController {
private service = new UserService();
public store = async (req: Request, res: Response) => {
const userRequest = new CreateUserRequest(req);
const result = await this.service.registerUser(userRequest.toDto());
if (result.isError()) {
return ResponseHelper.error(res, result.getMessage()!, HttpResponse.HTTP_BAD_REQUEST);
}
return ResponseHelper.json(res, result.getData(), HttpResponse.HTTP_CREATED);
}
}6. The Routes (with Validation Middleware)
import { Router } from 'express';
import { UserController } from '../controllers/UserController';
import { CreateUserSchema } from '../requests/CreateUserRequest';
import { validateDto } from 'seven365-http-foundation';
const router = Router();
const userController = new UserController();
/**
* POST /api/users
* Validates request body against CreateUserSchema before passing to controller.
*
* Example request:
* {
* "email": "[email protected]",
* "username": "john_doe"
* }
*
* On validation error (HTTP 422):
* {
* "success": false,
* "message": "Validation Error: email must be a valid email, username must be at least 3 characters"
* }
*/
router.post('/users', validateDto(CreateUserSchema), userController.store);
export default router;How ValidateDto Middleware Works
The validateDto middleware:
- Validates incoming request body against a Joi schema
- Strips unknown fields for security (removes unexpected properties)
- Rejects invalid fields with detailed error messages
- Replaces req.body with sanitized data before passing to controller
- Returns standardized errors using
ResponseHelperon validation failure
Features:
- ✅ Security: Prevents injection of unknown fields
- ✅ Sanitization: Automatically cleans request data
- ✅ Detailed errors: Maps all Joi validation errors
- ✅ Type-safe: Works seamlessly with TypeScript
Key Features
- BaseRequest: Type-safe casting (getString, getInt, getBoolean) and MongoDB-specific helpers like getMongoId.
- ServiceResponse: Standardized return type for services to prevent leaky abstractions.
- HttpResponse: Full list of Symfony-style HTTP status constants.
- ResponseHelper: Concise methods for consistent JSON API responses.
Requirements
- Node.js >= 14
- Express >= 4.17
- Joi >= 17.0.0
License
MIT
Author
Billy Joel Ranario
