OpenAPI / Swagger 文件生成
API 文件不應該手寫——手寫的文件一定會和實際行為脫節。各框架的自動生成方式:
FastAPI:零設定,內建
# 什麼都不需要做,/docs 和 /redoc 自動可用
app = FastAPI(
title="My API",
description="User management API",
version="1.0.0",
)
@app.post("/users", response_model=UserResponse, status_code=201,
summary="Create a new user",
responses={400: {"model": ErrorResponse}},
)
async def create_user(user: UserCreate):
...FastAPI 的 OpenAPI 是從 Pydantic schema 推斷的,不需要額外標注。
NestJS:@nestjs/swagger
import { ApiOperation, ApiResponse, ApiBody } from '@nestjs/swagger';
@Post()
@ApiOperation({ summary: 'Create a new user' })
@ApiBody({ type: CreateUserDto })
@ApiResponse({ status: 201, type: UserDto })
@ApiResponse({ status: 400, description: 'Validation error' })
create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
// main.ts — 設定 Swagger
const config = new DocumentBuilder()
.setTitle('My API')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);NestJS 需要在 handler 上加 @Api* annotation,比 FastAPI 多幾行,但比手寫 YAML 好太多。
Spring Boot:springdoc-openapi
// build.gradle
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.x'
// application.yml
springdoc:
api-docs:
path: /api-docs
swagger-ui:
path: /swagger-ui.html
// Controller 加 annotation(可選,不加也有基本文件)
@Operation(summary = "Create a new user")
@ApiResponse(responseCode = "201", description = "User created")
@PostMapping
public UserDto create(@RequestBody @Valid UserCreateDto dto) { ... }Spring Boot 只需要加一個依賴就有 /swagger-ui.html,非常省事。
Express:需要自己選
Express 沒有自動生成,主流選項:
- swagger-jsdoc:在 route / controller 加 JSDoc annotation,從 JSDoc 生成 OpenAPI YAML
- tsoa:TypeScript decorator + class 定義,compile time 生成 routes 和 swagger
- Hono
hono/zod-openapi:zod schema + Hono 的整合,自動生成 OpenAPI
DI Container Debug
當 NestJS / Spring 的 DI 出問題(circular dependency、Bean not found),錯誤訊息通常不直觀。
NestJS:找 circular dependency
# NestJS 的錯誤訊息會說 "Nest can't resolve dependencies of..."
# 加 forwardRef 解 circular reference
@Injectable()
export class UserService {
constructor(
@Inject(forwardRef(() => EmailService))
private emailService: EmailService,
) {}
}NestJS 的 @nestjs/core 提供了 NestFactory.createApplicationContext() 讓你在不啟 HTTP server 的情況下 debug DI 設定:
const app = await NestFactory.createApplicationContext(AppModule);
const userService = app.get(UserService);
// 確認 UserService 能被正確解析Spring:Actuator 查 Bean
Spring Boot Actuator 的 /actuator/beans endpoint 列出所有 Bean 和它們的依賴關係,對 debug DI 非常有用:
# application.yml
management:
endpoints:
web:
exposure:
include: beans, health, info框架專屬 Lint 規則
NestJS:eslint-plugin-nestjs
檢查:
- Module 沒有正確 export 但被其他 module import
@Injectable()少標- 在 constructor 裡做 async 操作(應該放在
onModuleInit)
Spring:SonarQube / Spring 專屬規則
SonarQube 有 Spring-specific 規則:
@Transactional加在privatemethod 上(Spring proxy 不會攔截,transaction 不生效)@Autowired用在 field 而非 constructor(不建議,難 test)- Bean 在 test context 沒有正確 mock
Python FastAPI:mypy + pylance + pydantic 驗證
FastAPI + Pydantic 最重要的工具是 mypy 靜態型別檢查:
mypy app/ --strictPylance(VS Code)的 Pydantic plugin 讓 IDE 知道 Pydantic model 的欄位型別,有 auto-complete 和錯誤提示。
開發輔助工具清單
| 框架 | CLI | Hot Reload | DB GUI | API Testing |
|---|---|---|---|---|
| Express | 無(ts-node-dev / nodemon) | ts-node-dev | TablePlus / pgAdmin | Postman / Bruno |
| FastAPI | 無(uvicorn —reload) | uvicorn —reload | TablePlus / pgAdmin | /docs 內建 |
| NestJS | @nestjs/cli(nest g controller) | ts-node-dev | TablePlus | Swagger UI |
| Spring Boot | Spring Initializr | Spring DevTools | IntelliJ DB Tool | Swagger UI |
| Laravel | Artisan CLI(php artisan make:*) | 無(FPM 每次都是新 process) | TablePlus | Swagger(需額外設定) |
