A lightweight TypeScript library that provides decorators and utilities for building Express.js applications with a class-based, annotation-driven architecture. Inspired by modern frameworks like NestJS, it enables you to write clean, maintainable, and type-safe API code.
- 🎯 Decorator-based routing - Define routes using
@Controller,@Get,@Post,@Put,@Deletedecorators - 🔌 Dependency Injection - Built-in service container with
@Injectdecorator - 🛡️ Middleware Support - Apply middleware at controller and route levels with
@Usedecorator - 📚 Route Documentation - Attach metadata to routes for API documentation generation
- 🔐 Type-safe - Full TypeScript support with type definitions included
- 📦 Zero dependencies - Minimal footprint with only
reflect-metadataas a dependency
npm install @cuy-stack/core
# or
yarn add @cuy-stack/core
# or
pnpm add @cuy-stack/core- Node.js 18+
- TypeScript 5.0+
- Express.js (peer dependency for type definitions)
{
"compilerOptions": {
"experimentalDecorators": true, // Enable decorator support
"emitDecoratorMetadata": true
// ... other options
}
}import express, { Request, Response, NextFunction } from 'express';
import { Controller, Get, Post, registerControllers } from '@cuy-stack/core';
@Controller('/users')
class UserController {
@Get('/')
getAllUsers(req: Request, res: Response, next: NextFunction) {
res.json({ users: [] });
}
@Post('/')
createUser(req: Request, res: Response, next: NextFunction) {
res.status(201).json({ id: 1, name: 'John Doe' });
}
}
// Initialize Express app
const app = express();
const router = express.Router();
// Register controllers
registerControllers(router, [UserController]);
app.use(router);
app.listen(3000, () => console.log('Server running on port 3000'));import { Controller, Get, Inject, serviceContainer } from '@cuy-stack/core';
class UserService {
getUsers() {
return [{ id: 1, name: 'John' }];
}
}
@Controller('/users')
class UserController {
@Inject('userService')
private userService!: UserService;
@Get('/')
getUsers(req: Request, res: Response) {
const users = this.userService.getUsers();
res.json(users);
}
}
// Register service before registering controllers
serviceContainer.register('userService', new UserService());
registerControllers(router, [UserController]);import { Controller, Get, Use } from '@cuy-stack/core';
const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
// Check authentication
next();
};
// Apply middleware to entire controller
@Controller('/admin', [authMiddleware])
class AdminController {
@Get('/')
getDashboard(req: Request, res: Response) {
res.json({ message: 'Admin dashboard' });
}
}
// Or apply middleware to specific routes
@Controller('/posts')
class PostController {
@Post('/')
@Use(authMiddleware)
createPost(req: Request, res: Response) {
res.json({ id: 1, title: 'New Post' });
}
}import { Controller, Get, RouteDoc } from '@cuy-stack/core';
@Controller('/api/users')
class UserController {
@Get('/', {
summary: 'Get all users',
description: 'Retrieve a list of all users in the system',
tags: ['users'],
response: {
200: {
description: 'List of users',
content: { type: 'array', schema: null },
},
},
})
getUsers(req: Request, res: Response) {
res.json([]);
}
}Defines a controller class that handles HTTP requests.
Parameters:
prefix(optional): URL prefix for all routes in this controller (e.g.,/users)middlewares(optional): Array of middleware functions to apply to all routes
@Controller('/api/users', [authMiddleware])
class UserController {}Defines route handlers for HTTP methods.
Parameters:
path: Route path relative to controller prefixdocumentation(optional): Route documentation metadata
@Get('/all', { summary: 'Get all items' })
getAllItems(req: Request, res: Response) { }Applies middleware to a controller or specific route handler.
@Get('/')
@Use(authMiddleware)
protectedRoute(req: Request, res: Response) { }Injects a service registered in the ServiceContainer.
@Inject('userService')
private userService!: UserService;Registers controller classes with an Express router.
const router = express.Router();
registerControllers(router, [UserController, PostController]);
app.use(router);Returns documentation for all registered routes.
const docs = getRouteDocumentation();
console.log(docs);Registers a service in the dependency injection container.
serviceContainer.register('userService', new UserService());Retrieves a registered service from the container.
const userService = serviceContainer.get<UserService>('userService');Documentation metadata for a route.
type RouteDoc = {
summary: string;
description: string;
body?: any;
auth_strategy?: AuthStrategy | null;
headers?: Record<string, string>;
response: Record<number | string, RouteDocResponse>;
tags: string[];
params?: Record<string, string>;
hide?: boolean;
};Authentication strategy information.
type AuthStrategy = {
name: string;
description: string;
value: Record<string, string>;
};Registered route documentation entry.
type RouteDocumentationEntry = {
method: 'get' | 'post' | 'put' | 'delete';
path: string;
handlerName: string;
documentation: RouteDoc | null;
};import express, {
type Request,
type Response,
type NextFunction,
} from 'express';
import {
Controller,
Get,
Post,
Use,
Inject,
registerControllers,
serviceContainer,
} from '@cuy-stack/core';
// Service layer
class UserService {
private users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
getAll() {
return this.users;
}
getById(id: number) {
return this.users.find((u) => u.id === id);
}
create(name: string) {
const user = { id: this.users.length + 1, name };
this.users.push(user);
return user;
}
}
// Middleware
const logger = (req: Request, res: Response, next: NextFunction) => {
console.log(`${req.method} ${req.path}`);
next();
};
// Controller
@Controller('/users', [logger])
class UserController {
@Inject('userService')
private userService!: UserService;
@Get('/')
getAll(req: Request, res: Response) {
const users = this.userService.getAll();
res.json(users);
}
@Get('/:id')
getById(req: Request, res: Response) {
const user = this.userService.getById(parseInt(req.params.id));
if (!user) {
res.status(404).json({ error: 'User not found' });
return;
}
res.json(user);
}
@Post('/')
create(req: Request, res: Response) {
const { name } = req.body;
const user = this.userService.create(name);
res.status(201).json(user);
}
}
// Setup
const app = express();
app.use(express.json());
// Register services
serviceContainer.register('userService', new UserService());
// Register routes
const router = express.Router();
registerControllers(router, [UserController]);
app.use(router);
// Start server
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});npm run build- Build the library using tsup (generates CJS and ESM bundles with types)npm run clean- Remove the dist folder
The library is built with:
- CommonJS format:
dist/index.js - ES Modules format:
dist/index.js - Type definitions:
dist/index.d.ts
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
For issues, questions, or suggestions, please open an issue on the repository.