| name | node-api-endpoint |
| description | Create Express.js API endpoint with controller, service, validation Use when this capability is needed. |
| metadata | {"author":"AdemKao"} |
Express API Endpoint Skill
Create RESTful API endpoints following Express.js best practices.
Workflow
1. Define Types
└─→ Request/response types
2. Create Validator
└─→ Zod schema for input
3. Create Service
└─→ Business logic
4. Create Controller
└─→ Request handling
5. Create Route
└─→ Wire everything together
6. Add Tests
└─→ Integration tests
File Structure
src/
├── types/user.types.ts
├── validators/user.validator.ts
├── services/user.service.ts
├── controllers/user.controller.ts
└── routes/user.routes.ts
Step 1: Types
export interface User {
id: string;
email: string;
name: string;
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserInput {
email: string;
name: string;
password: string;
}
export interface UpdateUserInput {
email?: string;
name?: string;
}
export interface UserResponse {
id: string;
email: string;
name: string;
createdAt: string;
}
Step 2: Validator
import { z } from 'zod';
export const createUserSchema = z.object({
email: z.string().email('Invalid email'),
name: z.string().min(1).max(100),
password: z.string().min(8),
});
export const updateUserSchema = z.object({
email: z.string().email().optional(),
name: z.string().min(1).max(100).optional(),
});
export const userIdParamSchema = z.object({
id: z.string().uuid('Invalid user ID'),
});
Step 3: Service
import { User, CreateUserInput, UpdateUserInput } from '../types/user.types';
import { prisma } from '../lib/prisma';
import { hashPassword } from '../utils/password';
import { AppError } from '../utils/errors';
export class UserService {
async findAll(): Promise<User[]> {
return prisma.user.findMany({
orderBy: { createdAt: 'desc' },
});
}
async findById(id: string): Promise<User | null> {
return prisma.user.findUnique({ where: { id } });
}
async create(input: CreateUserInput): Promise<User> {
const existing = await prisma.user.findUnique({
: { : input. },
});
(existing) {
(, , );
}
passwordHash = (input.);
prisma..({
: {
: input.,
: input.,
passwordHash,
},
});
}
(: , : ): <> {
prisma..({
: { id },
: input,
});
}
(: ): <> {
prisma..({ : { id } });
}
}
Step 4: Controller
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/user.service';
import { toUserResponse } from '../utils/transformers';
export class UserController {
constructor(private userService: UserService) {}
getAll = async (req: Request, res: Response, next: NextFunction) => {
try {
const users = await this.userService.findAll();
res.json({
data: users.map(toUserResponse)
});
} catch (error) {
next(error);
}
};
getById = async (req: Request, res: Response, next: NextFunction) => {
try {
const user = await ..(req..);
(!user) {
res.().({
: { : , : }
});
}
res.({ : (user) });
} (error) {
(error);
}
};
create = (: , : , : ) => {
{
user = ..(req.);
res.().({ : (user) });
} (error) {
(error);
}
};
update = (: , : , : ) => {
{
user = ..(req.., req.);
res.({ : (user) });
} (error) {
(error);
}
};
= (: , : , : ) => {
{
..(req..);
res.().();
} (error) {
(error);
}
};
}
Step 5: Route
import { Router } from 'express';
import { UserController } from '../controllers/user.controller';
import { UserService } from '../services/user.service';
import { validate } from '../middleware/validate.middleware';
import { authenticate } from '../middleware/auth.middleware';
import {
createUserSchema,
updateUserSchema,
userIdParamSchema,
} from '../validators/user.validator';
const router = Router();
const userService = new UserService();
const userController = new UserController(userService);
router.get('/',
authenticate,
userController.getAll
);
router.get('/:id',
authenticate,
validate({ params: userIdParamSchema }),
userController.getById
);
router.post('/',
authenticate,
validate({ body: createUserSchema }),
userController.create
);
router.patch('/:id',
authenticate,
validate({
: userIdParamSchema,
: updateUserSchema
}),
userController.
);
router.(,
authenticate,
({ : userIdParamSchema }),
userController.
);
router;
Step 6: Register Route
import { Router } from 'express';
import userRoutes from './user.routes';
const router = Router();
router.use('/users', userRoutes);
export default router;
Response Transformer
import { User, UserResponse } from '../types/user.types';
export function toUserResponse(user: User): UserResponse {
return {
id: user.id,
email: user.email,
name: user.name,
createdAt: user.createdAt.toISOString(),
};
}
Checklist
Source: AdemKao/ai-cowork — distributed by TomeVault.