Skill: Node.js/TypeScript Service
Purpose
Create or modify Node.js/TypeScript backend services with proper validation, error handling, logging, and testing.
Inputs
serviceName: Service or module identifierendpointSpec: HTTP method, path, request schema, response schemabusinessLogic: Description of what the endpoint doesframework: Express, Nest, Fastify (detected from project)
Outputs
- Route handler or controller file
- Validation schemas
- Error handling implementation
- Test file with unit and integration tests
Procedures
1. Detect Project Framework
Check package.json dependencies:
express→ Express.js@nestjs/core→ Nest.jsfastify→ Fastify
If unclear, request clarification.
2. Load Backend Policy
Read: .github/copilot-instructions/backend-policy.md
Follow Node.js/TypeScript conventions.
3. Define Request Validation Schema
Create validation schema using the project's validation library.
Common libraries:
- Zod
- Joi
- class-validator (Nest.js)
Example (Zod):
import { z } from 'zod'
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
age: z.number().int().positive().optional()
})
type CreateUserRequest = z.infer<typeof CreateUserSchema>
Refer to: references/validation-and-errors.md
4. Implement Route Handler
Structure varies by framework.
Express.js
import express, { Request, Response } from 'express'
router.post('/users', async (req: Request, res: Response) => {
try {
const data = CreateUserSchema.parse(req.body)
const user = await createUser(data)
res.status(201).json({ success: true, data: user })
} catch (error) {
handleError(error, res)
}
})
Nest.js
import { Controller, Post, Body } from '@nestjs/common'
import { CreateUserDto } from './dto/create-user.dto'
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
async create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto)
}
}
5. Implement Error Handling
Map errors to appropriate HTTP status codes:
- 400: Validation error, malformed request
- 401: Authentication required
- 403: Insufficient permissions
- 404: Resource not found
- 409: Conflict (duplicate resource)
- 500: Internal server error
Return structured error responses:
{
success: false,
error: {
code: 'VALIDATION_ERROR',
message: 'Invalid input data',
details: [...]
}
}
Refer to: references/validation-and-errors.md
6. Add Logging
Use structured logging (not console.log):
- Winston
- Pino
- Framework-specific loggers
logger.info('User created', { userId: user.id })
logger.error('Database connection failed', { error })
7. Implement Business Logic
Extract business logic to service layer (not in route handler):
class UsersService {
async create(data: CreateUserRequest): Promise<User> {
const existing = await this.findByEmail(data.email)
if (existing) {
throw new ConflictError('Email already registered')
}
return this.repository.save(data)
}
}
8. Generate Tests
Create test file adjacent to handler:
Unit Tests
Test business logic in isolation:
describe('UsersService', () => {
it('should create a user with valid data', async () => {
const data = { email: 'test@example.com', name: 'Test' }
const user = await service.create(data)
expect(user).toBeDefined()
expect(user.email).toBe(data.email)
})
it('should throw ConflictError for duplicate email', async () => {
await service.create({ email: 'test@example.com', name: 'Test' })
await expect(
service.create({ email: 'test@example.com', name: 'Test2' })
).rejects.toThrow(ConflictError)
})
})
Integration Tests
Test full HTTP request/response:
import request from 'supertest'
describe('POST /users', () => {
it('should create user and return 201', async () => {
const response = await request(app)
.post('/users')
.send({ email: 'test@example.com', name: 'Test' })
.expect(201)
expect(response.body.success).toBe(true)
expect(response.body.data.email).toBe('test@example.com')
})
it('should return 400 for invalid email', async () => {
const response = await request(app)
.post('/users')
.send({ email: 'invalid', name: 'Test' })
.expect(400)
expect(response.body.success).toBe(false)
})
})
9. Update Routing
Register the new endpoint in the application's routing configuration.
Verify no route conflicts exist.
10. Validate Implementation
Check:
- Request validation is applied
- Error handling is comprehensive
- Responses follow consistent structure
- Logging captures relevant context
- Tests cover success and error cases
Suggest verification commands:
npm run lintnpm testnpm run build
Error Handling
Missing validation library: Suggest installing Zod, Joi, or class-validator.
Framework mismatch: Clarify the detected framework and adjust implementation.
Route conflict: Notify and suggest alternative path or method.
Type safety issue: Ensure types are explicit and validated.
References
- Validation and Errors:
references/validation-and-errors.md - Service Specification Template:
assets/service-spec.template.md
Source: vanessamarely/ai-playbook-reposito — distributed by TomeVault.