Skip to content
Back to skills

Coding Express Api

ASecurity

Writes API endpoints with Express.js following layered architecture patterns. To be used for implementing RESTful endpoints with validation, error handling, and business logic.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
developmenttypescriptgoexpressapi

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 27, 2026

npx -y skills add David-Li0406/meta-skill-evloving --skill coding-express-api --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Coding Express Api?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Coding Express Api
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/david-li0406-coding-express-api/badge)](https://www.skillsdirectory.com/skills/david-li0406-coding-express-api)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: coding-express-api
description: >
  Writes API endpoints with Express.js following layered architecture patterns.
  To be used for implementing RESTful endpoints with validation, error handling, and business logic.
--- 

# Writing an Express API

Follow a **layered architecture** with clear separation of concerns between HTTP handling (routes), business logic (services), and data models (types).

## Layered Architecture Pattern

The application uses three main layers:

```
Routes (HTTP Layer)
    ↓
Services (Business Logic)
    ↓
Types (Domain Models)
```

## Project Structure

Organize code by technical layer:

```
src/
├── index.ts              # Express app setup, middleware, route registration
├── routes/               # HTTP layer - one file per resource
│   └── resource.ts       # Express Router with endpoint definitions
├── services/             # Business logic - one service per domain
│   └── resourceService.ts
├── types/                # Type definitions - one file per domain
│   └── resource.ts       # Interfaces, DTOs, and domain types
└── utils/                # Shared utilities (logging, helpers)
    └── logger.ts
```

## Routes Layer

### File Naming
- Use kebab-case: `rockets.ts`, `astronauts.ts`
- One route file per resource
- Use `.ts` extension (no `.routes` suffix needed)

### Route Handler Pattern

Routes instantiate a service and delegate HTTP concerns:
- Extract and validate request data
- Call service methods
- Return appropriate HTTP status codes and response bodies
- Use error handling with try-catch for robustness

See [controller.ts](./controller.ts) template for complete example implementation.

### HTTP Status Codes

| Method | Success | Validation Error | Not Found |
|--------|---------|------------------|-----------|
| GET    | 200     | N/A              | 404       |
| POST   | 201     | 400              | N/A       |
| PUT    | 200     | 400              | 404       |
| DELETE | 204     | N/A              | 404       |

### Error Response Format

Return validation errors as an array:

```typescript
res.status(400).json({
  errors: [
    { field: 'name', message: 'Name is required' },
    { field: 'price', message: 'Price must be positive' }
  ]
});
```

## Services Layer

### File Naming
- Use kebab-case with `.service` suffix: `rocket.service.ts`, `astronaut.service.ts`
- One service class per domain

### Service Pattern

Services encapsulate all business logic for a resource:
- Manage in-memory Map storage with auto-incrementing ID generation
- Implement CRUD methods (create, getById, getAll, update, delete)
- Provide separate validation methods that return all errors at once
- Use consistent error throwing for exceptional conditions
- Log important operations with component context

Key patterns:
- **IDs**: Generate with pattern `resource-${incrementingId++}`
- **Validation**: Return array of `{ field, message }` objects, never throw validation errors
- **Updates**: Include `updatedAt` timestamp, merge request with existing data
- **Deletion**: Idempotent (safe to call multiple times on same ID)

See [service.ts](./service.ts) template for complete example implementation.

## Types Layer

### File Naming
- Use kebab-case: `rocket.ts`, `astronaut.ts`
- One type file per domain

### Type Definitions

Organize types into three categories:
- **Domain Entity**: The resource as stored (includes id, timestamps)
- **Request DTOs**: Input contracts for create and update operations
- **Error Types**: Validation and error response structures

Use literal unions for enums and optional fields for partial updates.

See [types.ts](./types.ts) template for complete example implementation.

### Type Guidelines

- Use separate request/response types (DTO pattern)
- Define enums or literal unions for fixed values (prefer unions: `'active' | 'inactive' | 'retired'`)
- Use `readonly` for immutable properties
- Avoid `any` type - use strict typing
- Export interfaces, not type aliases for public contracts

## Utils Layer

### Common Utilities

Utilities provide cross-cutting concerns like logging and helpers:

```typescript
// logger.ts
export const logger = {
  info(component: string, message: string, data?: unknown): void {
    console.log(`[${component}] ${message}`, data ? JSON.stringify(data) : '');
  },
  error(component: string, message: string, data?: unknown): void {
    console.error(`[${component}] ERROR: ${message}`, data ? JSON.stringify(data) : '');
  },
  warn(component: string, message: string, data?: unknown): void {
    console.warn(`[${component}] WARN: ${message}`, data ? JSON.stringify(data) : '');
  },
};
```

Key patterns:
- Keep utilities simple and focused
- Provide consistent interfaces across the app
- Use for shared validation, formatting, or constants

## Application Setup

### Index Entry Point

The entry point (`src/index.ts`) sets up Express with middleware and registers route handlers:

```typescript
import express from 'express';
import rocketsRouter from './routes/rockets';
import { logger } from './utils/logger';

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

app.get('/', (req, res) => {
  res.status(200).json({ status: 'ok', message: 'AstroBookings API' });
});

app.get('/health', (req, res) => {
  res.status(200).json({ status: 'ok' });
});

app.use('/rockets', rocketsRouter);

app.listen(PORT, () => {
  logger.info('Server', `Running on port ${PORT}`);
});

export default app;
```

Key patterns:
- One line per route registration
- JSON middleware should be first after app creation
- Include health check endpoints
- Log server startup with port

## Best Practices

1. **Validation**: Always validate and return all errors in one response
2. **Error Handling**: Use try-catch for async operations, throw descriptive errors
3. **Status Codes**: Use correct HTTP status codes (201 for created, 204 for deleted, etc.)
4. **Logging**: Log important operations with context
5. **Type Safety**: Use strict typing, avoid `any`
6. **Single Responsibility**: Keep routes thin, move logic to services
7. **Separation of Concerns**: Don't mix HTTP logic with business logic
8. **ID Generation**: Use service-generated IDs with pattern `resource-${incrementingId}`

Files in this skill

  • SKILL.md6.2 KB
  • controller.ts2.2 KB
  • service.ts3.4 KB
  • types.ts1002 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…