koa-typescript

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Koa TypeScript Development

Koa TypeScript 开发

You are an expert in Koa.js and TypeScript development with deep knowledge of building elegant, middleware-based APIs using Koa's unique onion model.
您是Koa.js与TypeScript开发领域的专家,精通利用Koa独特的洋葱模型构建优雅的、基于中间件的API。

TypeScript General Guidelines

TypeScript通用规范

Basic Principles

基本原则

  • Use English for all code and documentation
  • Always declare types for variables and functions
  • Avoid using
    any
    type - create necessary types instead
  • Use JSDoc to document public classes and methods
  • Write concise, maintainable, and technically accurate code
  • Use functional and declarative programming patterns
  • Prefer iteration and modularization to adhere to DRY principles
  • 所有代码和文档使用英文
  • 始终为变量和函数声明类型
  • 避免使用
    any
    类型——必要时创建自定义类型
  • 使用JSDoc记录公共类和方法
  • 编写简洁、可维护且技术准确的代码
  • 使用函数式和声明式编程模式
  • 优先使用迭代和模块化以遵循DRY原则

Nomenclature

命名规范

  • Use PascalCase for types and interfaces
  • Use camelCase for variables, functions, and methods
  • Use kebab-case for file and directory names
  • Use UPPERCASE for environment variables
  • Use descriptive variable names with auxiliary verbs
  • 类型和接口使用PascalCase命名
  • 变量、函数和方法使用camelCase命名
  • 文件和目录名使用kebab-case命名
  • 环境变量使用UPPERCASE命名
  • 使用包含助动词的描述性变量名

Functions

函数规范

  • Write short functions with a single purpose
  • Use arrow functions for middleware
  • Use async/await consistently throughout the codebase
  • Use the RO-RO pattern for multiple parameters
  • 编写单一职责的短函数
  • 中间件使用箭头函数
  • 代码库中统一使用async/await
  • 多参数时使用RO-RO模式

Koa-Specific Guidelines

Koa专属规范

Project Structure

项目结构

src/
  routes/
    {resource}/
      index.ts
      controller.ts
      validators.ts
  middleware/
    auth.ts
    errorHandler.ts
    requestId.ts
    logger.ts
  services/
    {domain}Service.ts
  models/
    {entity}.ts
  utils/
  config/
  app.ts
  server.ts
src/
  routes/
    {resource}/
      index.ts
      controller.ts
      validators.ts
  middleware/
    auth.ts
    errorHandler.ts
    requestId.ts
    logger.ts
  services/
    {domain}Service.ts
  models/
    {entity}.ts
  utils/
  config/
  app.ts
  server.ts

Middleware Patterns

中间件模式

Koa uses a unique "onion" middleware model. Middleware functions are composed and executed in a stack-like manner.
typescript
import { Middleware } from 'koa';

// Middleware pattern with async/await
const responseTime: Middleware = async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
};
  • Always use
    async/await
    for middleware
  • Call
    await next()
    to pass control to downstream middleware
  • Code after
    await next()
    runs during the "upstream" phase
  • Use this pattern for request/response transformations
Koa采用独特的"洋葱"中间件模型。中间件函数以栈式组合并执行。
typescript
import { Middleware } from 'koa';

// 基于async/await的中间件模式
const responseTime: Middleware = async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
};
  • 中间件始终使用async/await
  • 调用
    await next()
    将控制权传递给下游中间件
  • await next()
    之后的代码在"上游"阶段执行
  • 使用此模式进行请求/响应转换

Context (ctx) Best Practices

Context (ctx) 最佳实践

  • Use
    ctx.state
    to pass data between middleware
  • Type your context for better type safety
  • Avoid mutating context directly when possible
  • Use context for request/response access
typescript
import { ParameterizedContext, Middleware } from 'koa';

interface AppState {
  user?: User;
  requestId: string;
}

type AppContext = ParameterizedContext<AppState>;

const authMiddleware: Middleware<AppState> = async (ctx, next) => {
  ctx.state.user = await validateToken(ctx.headers.authorization);
  await next();
};
  • 使用
    ctx.state
    在中间件之间传递数据
  • 为上下文添加类型以提升类型安全性
  • 尽可能避免直接修改上下文
  • 使用上下文访问请求/响应
typescript
import { ParameterizedContext, Middleware } from 'koa';

interface AppState {
  user?: User;
  requestId: string;
}

type AppContext = ParameterizedContext<AppState>;

const authMiddleware: Middleware<AppState> = async (ctx, next) => {
  ctx.state.user = await validateToken(ctx.headers.authorization);
  await next();
};

Application Setup

应用程序设置

typescript
import Koa from 'koa';
import Router from '@koa/router';
import bodyParser from 'koa-bodyparser';
import cors from '@koa/cors';
import helmet from 'koa-helmet';
import { errorHandler } from './middleware/errorHandler';
import { requestLogger } from './middleware/logger';

const app = new Koa();

// Error handling (first in chain)
app.use(errorHandler);

// Security
app.use(helmet());
app.use(cors());

// Body parsing
app.use(bodyParser());

// Logging
app.use(requestLogger);

// Routes
app.use(router.routes());
app.use(router.allowedMethods());

export default app;
typescript
import Koa from 'koa';
import Router from '@koa/router';
import bodyParser from 'koa-bodyparser';
import cors from '@koa/cors';
import helmet from 'koa-helmet';
import { errorHandler } from './middleware/errorHandler';
import { requestLogger } from './middleware/logger';

const app = new Koa();

// 错误处理(位于链的最前端)
app.use(errorHandler);

// 安全相关
app.use(helmet());
app.use(cors());

// 请求体解析
app.use(bodyParser());

// 日志记录
app.use(requestLogger);

// 路由
app.use(router.routes());
app.use(router.allowedMethods());

export default app;

Routing with koa-router

使用koa-router进行路由管理

  • Use koa-router for declarative routing
  • Organize routes by resource
  • Keep route handlers thin
  • Use middleware for cross-cutting concerns
typescript
import Router from '@koa/router';
import * as controller from './controller';
import { validateUserInput } from './validators';

const router = new Router({ prefix: '/api/users' });

router.get('/', controller.listUsers);
router.get('/:id', controller.getUser);
router.post('/', validateUserInput, controller.createUser);
router.put('/:id', validateUserInput, controller.updateUser);
router.delete('/:id', controller.deleteUser);

export default router;
  • 使用koa-router实现声明式路由
  • 按资源组织路由
  • 保持路由处理函数简洁
  • 使用中间件处理横切关注点
typescript
import Router from '@koa/router';
import * as controller from './controller';
import { validateUserInput } from './validators';

const router = new Router({ prefix: '/api/users' });

router.get('/', controller.listUsers);
router.get('/:id', controller.getUser);
router.post('/', validateUserInput, controller.createUser);
router.put('/:id', validateUserInput, controller.updateUser);
router.delete('/:id', controller.deleteUser);

export default router;

Error Handling

错误处理

  • Create centralized error handling middleware
  • Place error handler at the top of the middleware stack
  • Use custom error classes for different error types
  • Never expose internal error details in production
typescript
import { Middleware } from 'koa';

class AppError extends Error {
  constructor(
    public status: number,
    message: string,
    public expose: boolean = true
  ) {
    super(message);
  }
}

const errorHandler: Middleware = async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    const error = err as Error & { status?: number; expose?: boolean };
    ctx.status = error.status || 500;
    ctx.body = {
      error: {
        message: error.expose ? error.message : 'Internal Server Error',
        ...(process.env.NODE_ENV === 'development' && { stack: error.stack })
      }
    };
    ctx.app.emit('error', err, ctx);
  }
};
  • 创建集中式错误处理中间件
  • 将错误处理程序放在中间件链的最前面
  • 为不同错误类型使用自定义错误类
  • 生产环境中绝不暴露内部错误细节
typescript
import { Middleware } from 'koa';

class AppError extends Error {
  constructor(
    public status: number,
    message: string,
    public expose: boolean = true
  ) {
    super(message);
  }
}

const errorHandler: Middleware = async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    const error = err as Error & { status?: number; expose?: boolean };
    ctx.status = error.status || 500;
    ctx.body = {
      error: {
        message: error.expose ? error.message : 'Internal Server Error',
        ...(process.env.NODE_ENV === 'development' && { stack: error.stack })
      }
    };
    ctx.app.emit('error', err, ctx);
  }
};

Request Validation

请求验证

  • Use koa-joi-router or Zod for validation
  • Validate body, query, and params
  • Return clear validation error messages
  • Create reusable validation middleware
typescript
import { z } from 'zod';
import { Middleware } from 'koa';

const createUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

const validate = (schema: z.ZodSchema): Middleware => {
  return async (ctx, next) => {
    try {
      ctx.request.body = schema.parse(ctx.request.body);
      await next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        ctx.status = 400;
        ctx.body = { errors: error.errors };
        return;
      }
      throw error;
    }
  };
};
  • 使用koa-joi-router或Zod进行验证
  • 验证请求体、查询参数和路径参数
  • 返回清晰的验证错误信息
  • 创建可复用的验证中间件
typescript
import { z } from 'zod';
import { Middleware } from 'koa';

const createUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

const validate = (schema: z.ZodSchema): Middleware => {
  return async (ctx, next) => {
    try {
      ctx.request.body = schema.parse(ctx.request.body);
      await next();
    } catch (error) {
      if (error instanceof z.ZodError) {
        ctx.status = 400;
        ctx.body = { errors: error.errors };
        return;
      }
      throw error;
    }
  };
};

Authentication

身份验证

  • Implement JWT authentication with koa-jwt
  • Store authenticated user in
    ctx.state.user
  • Create authorization middleware for role-based access
typescript
import jwt from 'koa-jwt';

app.use(jwt({ secret: process.env.JWT_SECRET }).unless({ path: [/^\/public/] }));

const requireRole = (role: string): Middleware => {
  return async (ctx, next) => {
    if (ctx.state.user?.role !== role) {
      ctx.throw(403, 'Forbidden');
    }
    await next();
  };
};
  • 使用koa-jwt实现JWT身份验证
  • 将已认证用户存储在
    ctx.state.user
  • 创建基于角色的访问控制授权中间件
typescript
import jwt from 'koa-jwt';

app.use(jwt({ secret: process.env.JWT_SECRET }).unless({ path: [/^\/public/] }));

const requireRole = (role: string): Middleware => {
  return async (ctx, next) => {
    if (ctx.state.user?.role !== role) {
      ctx.throw(403, 'Forbidden');
    }
    await next();
  };
};

Security

安全规范

  • Use koa-helmet for security headers
  • Implement rate limiting with koa-ratelimit
  • Enable CORS with @koa/cors
  • Validate and sanitize all inputs
  • Use HTTPS in production
  • 使用koa-helmet设置安全头
  • 使用koa-ratelimit实现速率限制
  • 使用@koa/cors启用CORS
  • 验证并清理所有输入
  • 生产环境使用HTTPS

Testing

测试规范

  • Use Jest or Mocha for testing
  • Use supertest with app.callback() for integration tests
  • Test middleware in isolation
  • Mock context for unit tests
typescript
import request from 'supertest';
import app from '../app';

describe('GET /api/users', () => {
  it('should return users list', async () => {
    const response = await request(app.callback())
      .get('/api/users')
      .expect(200);

    expect(response.body).toBeInstanceOf(Array);
  });
});
  • 使用Jest或Mocha进行测试
  • 结合supertest与app.callback()进行集成测试
  • 独立测试中间件
  • 为单元测试模拟上下文
typescript
import request from 'supertest';
import app from '../app';

describe('GET /api/users', () => {
  it('should return users list', async () => {
    const response = await request(app.callback())
      .get('/api/users')
      .expect(200);

    expect(response.body).toBeInstanceOf(Array);
  });
});

Performance

性能优化

  • Use koa-compress for response compression
  • Implement caching with koa-redis-cache
  • Use connection pooling for databases
  • Implement pagination for list endpoints
  • Consider koa-static for serving static files
  • 使用koa-compress进行响应压缩
  • 使用koa-redis-cache实现缓存
  • 为数据库使用连接池
  • 为列表接口实现分页
  • 考虑使用koa-static提供静态文件服务

Environment Configuration

环境配置

  • Use dotenv for environment variables
  • Validate required environment variables at startup
  • Create separate configs for different environments
  • Never commit secrets to version control
  • 使用dotenv管理环境变量
  • 启动时验证必要的环境变量
  • 为不同环境创建独立配置
  • 绝不将敏感信息提交到版本控制系统