Backend API implementation patterns for scalability, security, and maintainability. Use when building APIs, services, and backend systems.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill backend-api-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Backend Api Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-backend-api-patterns-claude-skill-registry)More formats (shields.io, HTML) on the badges page.
---
name: backend-api-patterns
description: Backend API implementation patterns for scalability, security, and maintainability. Use when building APIs, services, and backend systems.
---
# Backend API Patterns
Implementation patterns for scalable, secure, and maintainable backend systems.
## When to Use
- Building new API endpoints
- Implementing service layer logic
- Database operations and queries
- Authentication and authorization
## Service Layer Patterns
### Repository Pattern
```typescript
// Separate data access from business logic
interface UserRepository {
findById(id: string): Promise<User | null>
findByEmail(email: string): Promise<User | null>
create(data: CreateUserDto): Promise<User>
update(id: string, data: UpdateUserDto): Promise<User>
delete(id: string): Promise<void>
}
class UserService {
constructor(private readonly userRepo: UserRepository) {}
async createUser(dto: CreateUserDto): Promise<User> {
// Business logic here
const existing = await this.userRepo.findByEmail(dto.email)
if (existing) throw new ConflictError('Email already exists')
return this.userRepo.create(dto)
}
}
```
### Unit of Work Pattern
```typescript
// Manage transactions across repositories
interface UnitOfWork {
users: UserRepository
orders: OrderRepository
commit(): Promise<void>
rollback(): Promise<void>
}
async function createOrderWithUser(uow: UnitOfWork, data: OrderData) {
try {
const user = await uow.users.create(data.user)
const order = await uow.orders.create({ ...data.order, userId: user.id })
await uow.commit()
return { user, order }
} catch (error) {
await uow.rollback()
throw error
}
}
```
## Error Handling
### Custom Error Classes
```typescript
abstract class AppError extends Error {
abstract statusCode: number
abstract code: string
}
class NotFoundError extends AppError {
statusCode = 404
code = 'NOT_FOUND'
constructor(resource: string, id: string) {
super(`${resource} with id ${id} not found`)
}
}
class ValidationError extends AppError {
statusCode = 422
code = 'VALIDATION_ERROR'
constructor(public errors: FieldError[]) {
super('Validation failed')
}
}
```
### Global Error Handler
```typescript
function errorHandler(error: Error, req: Request, res: Response, next: Next) {
if (error instanceof AppError) {
return res.status(error.statusCode).json({
error: {
code: error.code,
message: error.message,
details: error instanceof ValidationError ? error.errors : undefined
}
})
}
// Log unexpected errors
logger.error('Unexpected error', { error, requestId: req.id })
return res.status(500).json({
error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' }
})
}
```
## Database Patterns
### Query Optimization
```typescript
// ❌ N+1 Query Problem
const users = await db.users.findMany()
for (const user of users) {
user.orders = await db.orders.findMany({ where: { userId: user.id } })
}
// ✅ Eager Loading
const users = await db.users.findMany({
include: { orders: true }
})
// ✅ Or batch loading
const users = await db.users.findMany()
const orders = await db.orders.findMany({
where: { userId: { in: users.map(u => u.id) } }
})
```
### Connection Pooling
```typescript
const pool = {
min: 2,
max: 10,
idleTimeoutMs: 30000,
acquireTimeoutMs: 30000
}
```
## Security Patterns
### Input Validation
```typescript
// Always validate at the boundary
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
password: z.string().min(8).regex(/[A-Z]/).regex(/[0-9]/)
})
async function createUser(req: Request) {
const validated = CreateUserSchema.parse(req.body)
// Safe to use validated data
}
```
### Authorization
```typescript
// Resource-level authorization
async function getOrder(userId: string, orderId: string) {
const order = await orderRepo.findById(orderId)
if (!order) throw new NotFoundError('Order', orderId)
if (order.userId !== userId) throw new ForbiddenError()
return order
}
```
## Performance Patterns
### Caching Strategy
```typescript
async function getUserById(id: string): Promise<User> {
// Check cache first
const cached = await cache.get(`user:${id}`)
if (cached) return JSON.parse(cached)
// Fetch from database
const user = await userRepo.findById(id)
if (!user) throw new NotFoundError('User', id)
// Store in cache with TTL
await cache.set(`user:${id}`, JSON.stringify(user), 'EX', 3600)
return user
}
```
### Rate Limiting
```typescript
const rateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per window
message: { error: { code: 'RATE_LIMITED', message: 'Too many requests' } }
})
```
## Logging Standards
```typescript
// Structured logging
logger.info('User created', {
userId: user.id,
email: user.email,
requestId: req.id,
duration: Date.now() - startTime
})
// Log levels
logger.debug() // Development details
logger.info() // Business events
logger.warn() // Potential issues
logger.error() // Errors needing attention
```
## Checklist
Before completing backend implementation:
- [ ] Input validated with schema
- [ ] Errors properly categorized
- [ ] Database queries optimized (no N+1)
- [ ] Authorization checks in place
- [ ] Sensitive data not logged
- [ ] Transaction boundaries defined
- [ ] Caching strategy considered
- [ ] Rate limiting configured
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!