extract-openapi-from-code
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseextract-openapi-from-code
从代码中提取OpenAPI规范
Extract an OpenAPI specification from an existing API codebase. Covers eight major frameworks across Python, Java, JavaScript/TypeScript, Ruby, and PHP.
从现有API代码库中提取OpenAPI规范。涵盖Python、Java、JavaScript/TypeScript、Ruby和PHP这几种语言下的8个主流框架。
Content Guides
内容指南
| Framework | Language | Guide |
|---|---|---|
| FastAPI | Python | content/frameworks/fastapi.md |
| Flask | Python | content/frameworks/flask.md |
| Django REST Framework | Python | content/frameworks/django.md |
| Spring Boot | Java | content/frameworks/spring-boot.md |
| NestJS | TypeScript | content/frameworks/nestjs.md |
| Hono | TypeScript | content/frameworks/hono.md |
| Rails | Ruby | content/frameworks/rails.md |
| Laravel | PHP | content/frameworks/laravel.md |
Each guide provides detailed setup, schema definition, Speakeasy extensions, authentication, and troubleshooting for that framework.
| 框架 | 语言 | 指南 |
|---|---|---|
| FastAPI | Python | content/frameworks/fastapi.md |
| Flask | Python | content/frameworks/flask.md |
| Django REST Framework | Python | content/frameworks/django.md |
| Spring Boot | Java | content/frameworks/spring-boot.md |
| NestJS | TypeScript | content/frameworks/nestjs.md |
| Hono | TypeScript | content/frameworks/hono.md |
| Rails | Ruby | content/frameworks/rails.md |
| Laravel | PHP | content/frameworks/laravel.md |
每个指南都提供了对应框架的详细设置、Schema定义、Speakeasy扩展、认证配置以及故障排查内容。
When to Use
适用场景
- User has an existing API and wants to generate an OpenAPI spec from it
- User wants to create an SDK from code that has no OpenAPI spec yet
- User mentions a specific framework (FastAPI, Flask, Django, Spring Boot, NestJS, Hono, Rails, Laravel)
- User says: "extract OpenAPI", "code first", "generate spec from code", "existing API code"
- 用户已有一个API,希望从中生成OpenAPI规范
- 用户想从没有OpenAPI规范的代码中创建SDK
- 用户提到了特定框架(FastAPI、Flask、Django、Spring Boot、NestJS、Hono、Rails、Laravel)
- 用户表述为:"extract OpenAPI"、"code first"、"从代码生成规范"、"现有API代码"
Inputs
输入参数
| Input | Required | Description |
|---|---|---|
| Framework | Yes | The API framework in use (see Decision Framework) |
| Project path | Yes | Root directory of the API project |
| Output path | No | Where to write the spec (default: |
| Target language | No | SDK target language, if generating an SDK after extraction |
| 输入项 | 是否必填 | 描述 |
|---|---|---|
| Framework | 是 | 当前使用的API框架(参考决策框架) |
| Project path | 是 | API项目的根目录 |
| Output path | 否 | 规范文件的输出路径(默认: |
| Target language | 否 | 提取后生成SDK的目标语言 |
Outputs
输出结果
| Output | Description |
|---|---|
| OpenAPI spec | A JSON or YAML file describing the API |
| Validation report | Lint results from |
| 输出项 | 描述 |
|---|---|
| OpenAPI spec | 描述API的JSON或YAML文件 |
| Validation report | 来自 |
Prerequisites
前置条件
- The API project must be buildable and its dependencies installed
- For runtime extraction (FastAPI, Spring Boot, NestJS, Hono), the app must be importable or startable
- CLI installed for post-extraction validation and SDK generation
speakeasy
- API项目必须可构建,且已安装所有依赖
- 对于运行时提取(FastAPI、Spring Boot、NestJS、Hono),应用必须可导入或可启动
- 已安装CLI,用于提取后的验证和SDK生成
speakeasy
Decision Framework
决策框架
Use this tree to determine the extraction method:
| Framework | Language | Method | Requires Running Server? |
|---|---|---|---|
| FastAPI | Python | Built-in export | No |
| Flask (flask-smorest) | Python | CLI command | No |
| Django REST Framework | Python | drf-spectacular CLI | No |
| Spring Boot (springdoc) | Java | HTTP endpoint | Yes |
| NestJS | TypeScript | HTTP endpoint or script | Yes |
| Hono (zod-openapi) | TypeScript | Programmatic export | No |
| Rails (rswag) | Ruby | Rake task | No |
| Laravel (l5-swagger) | PHP | Artisan command | No |
使用以下树形结构确定提取方法:
| 框架 | 语言 | 方法 | 是否需要运行服务器? |
|---|---|---|---|
| FastAPI | Python | 内置导出 | 否 |
| Flask (flask-smorest) | Python | CLI命令 | 否 |
| Django REST Framework | Python | drf-spectacular CLI | 否 |
| Spring Boot (springdoc) | Java | HTTP端点 | 是 |
| NestJS | TypeScript | HTTP端点或脚本 | 是 |
| Hono (zod-openapi) | TypeScript | 程序化导出 | 否 |
| Rails (rswag) | Ruby | Rake任务 | 否 |
| Laravel (l5-swagger) | PHP | Artisan命令 | 否 |
Command
命令示例
Choose the command matching your framework below. After extraction, always validate with .
speakeasy lint选择与你的框架匹配的命令。提取完成后,务必使用进行验证。
speakeasy lintPython: FastAPI
Python: FastAPI
FastAPI generates an OpenAPI schema at runtime. Export it without starting the server:
bash
python -c "import json; from myapp import app; print(json.dumps(app.openapi()))" > openapi.jsonReplace with the module containing your FastAPI instance. If the app uses a factory pattern:
myappappbash
python -c "import json; from myapp import create_app; app = create_app(); print(json.dumps(app.openapi()))" > openapi.jsonYou can also start the server and fetch from .
http://localhost:8000/openapi.jsonFastAPI会在运行时生成OpenAPI Schema。无需启动服务器即可导出:
bash
python -c "import json; from myapp import app; print(json.dumps(app.openapi()))" > openapi.json将替换为包含FastAPI 实例的模块。如果应用使用工厂模式:
myappappbash
python -c "import json; from myapp import create_app; app = create_app(); print(json.dumps(app.openapi()))" > openapi.json你也可以启动服务器,从获取。
http://localhost:8000/openapi.jsonPython: Flask (flask-smorest)
Python: Flask (flask-smorest)
Requires flask-smorest or apispec:
bash
flask openapi write openapi.jsonIf using apispec directly, export programmatically:
python
import json
from myapp import create_app, spec
app = create_app()
with app.app_context():
print(json.dumps(spec.to_dict()))需要依赖flask-smorest或apispec:
bash
flask openapi write openapi.json如果直接使用apispec,可通过程序化方式导出:
python
import json
from myapp import create_app, spec
app = create_app()
with app.app_context():
print(json.dumps(spec.to_dict()))Python: Django REST Framework
Python: Django REST Framework
Requires drf-spectacular:
bash
python manage.py spectacular --file openapi.yamlFor JSON output:
bash
python manage.py spectacular --format openapi-json --file openapi.json需要依赖drf-spectacular:
bash
python manage.py spectacular --file openapi.yaml如需JSON格式输出:
bash
python manage.py spectacular --format openapi-json --file openapi.jsonJava: Spring Boot
Java: Spring Boot
Requires springdoc-openapi. Start the application, then fetch the spec:
bash
undefined需要依赖springdoc-openapi。启动应用后,获取规范:
bash
undefinedStart the app (background)
启动应用(后台运行)
./mvnw spring-boot:run &
./mvnw spring-boot:run &
Wait for startup
等待启动完成
sleep 15
sleep 15
Fetch the spec
获取规范
curl http://localhost:8080/v3/api-docs -o openapi.json
curl http://localhost:8080/v3/api-docs -o openapi.json
For YAML format
如需YAML格式
curl http://localhost:8080/v3/api-docs.yaml -o openapi.yaml
curl http://localhost:8080/v3/api-docs.yaml -o openapi.yaml
Stop the app
停止应用
kill %1
If the server runs on a different port or context path, adjust the URL accordingly.kill %1
如果服务器运行在不同端口或上下文路径,请相应调整URL。TypeScript: NestJS
TypeScript: NestJS
Requires @nestjs/swagger. Start the application, then fetch:
bash
undefined需要依赖@nestjs/swagger。启动应用后,获取规范:
bash
undefinedStart the app (background)
启动应用(后台运行)
npm run start &
sleep 10
npm run start &
sleep 10
Fetch the spec (default path with SwaggerModule)
获取规范(SwaggerModule默认路径)
curl http://localhost:3000/api-json -o openapi.json
curl http://localhost:3000/api-json -o openapi.json
Stop the app
停止应用
kill %1
Alternatively, create a script to export without running the server:
```typescript
// scripts/export-openapi.ts
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from '../src/app.module';
import * as fs from 'fs';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { logger: false });
const config = new DocumentBuilder().setTitle('API').build();
const doc = SwaggerModule.createDocument(app, config);
fs.writeFileSync('openapi.json', JSON.stringify(doc, null, 2));
await app.close();
}
bootstrap();kill %1
或者,创建脚本无需启动服务器即可导出:
```typescript
// scripts/export-openapi.ts
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from '../src/app.module';
import * as fs from 'fs';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { logger: false });
const config = new DocumentBuilder().setTitle('API').build();
const doc = SwaggerModule.createDocument(app, config);
fs.writeFileSync('openapi.json', JSON.stringify(doc, null, 2));
await app.close();
}
bootstrap();TypeScript: Hono (zod-openapi)
TypeScript: Hono (zod-openapi)
Requires @hono/zod-openapi. Export the schema programmatically:
typescript
// scripts/export-openapi.ts
import { app } from '../src/app';
import * as fs from 'fs';
const doc = app.doc('/doc', {
openapi: '3.1.0',
info: { title: 'API', version: '1.0.0' },
});
fs.writeFileSync('openapi.json', JSON.stringify(doc, null, 2));Run with:
bash
npx tsx scripts/export-openapi.ts需要依赖@hono/zod-openapi。通过程序化方式导出Schema:
typescript
// scripts/export-openapi.ts
import { app } from '../src/app';
import * as fs from 'fs';
const doc = app.doc('/doc', {
openapi: '3.1.0',
info: { title: 'API', version: '1.0.0' },
});
fs.writeFileSync('openapi.json', JSON.stringify(doc, null, 2));运行脚本:
bash
npx tsx scripts/export-openapi.tsRuby: Rails (rswag)
Ruby: Rails (rswag)
Requires rswag:
bash
rails rswag:specs:swaggerizeThe spec is written to by default (configurable in ).
swagger/v1/swagger.yamlconfig/initializers/rswag_api.rb需要依赖rswag:
bash
rails rswag:specs:swaggerize规范默认写入(可在中配置)。
swagger/v1/swagger.yamlconfig/initializers/rswag_api.rbPHP: Laravel (l5-swagger)
PHP: Laravel (l5-swagger)
Requires l5-swagger:
bash
php artisan l5-swagger:generateThe spec is written to by default.
storage/api-docs/api-docs.jsonPost-Extraction Steps
提取后步骤
After extracting the spec, always run these steps:
提取规范后,务必执行以下步骤:
1. Validate the spec
1. 验证规范
bash
speakeasy lint openapi --non-interactive -s openapi.jsonbash
speakeasy lint openapi --non-interactive -s openapi.json2. Fix issues with overlays (if needed)
2. 使用Overlay修复问题(如有需要)
If validation reveals issues, use an overlay rather than modifying the extracted spec directly:
bash
speakeasy overlay apply -s openapi.json -o fixes.yamlTo fix validation errors, create an OpenAPI overlay file and apply it with .
speakeasy overlay apply -s <spec> -o <overlay>如果验证发现问题,请使用Overlay而非直接修改提取的规范:
bash
speakeasy overlay apply -s openapi.json -o fixes.yaml如需修复验证错误,创建一个OpenAPI Overlay文件,然后使用命令应用。
speakeasy overlay apply -s <spec> -o <overlay>3. Generate an SDK
3. 生成SDK
bash
speakeasy quickstart --skip-interactive --output console \
-s openapi.json \
-t <target> \
-n <name> \
-p <package>Run to initialize a new SDK project.
speakeasy quickstart -s <spec> -t <language>bash
speakeasy quickstart --skip-interactive --output console \
-s openapi.json \
-t <target> \
-n <name> \
-p <package>运行初始化新的SDK项目。
speakeasy quickstart -s <spec> -t <language>Example
示例
Full workflow for a FastAPI project:
bash
undefinedFastAPI项目的完整工作流:
bash
undefined1. Extract the OpenAPI spec
1. 提取OpenAPI规范
cd /path/to/my-fastapi-project
python -c "import json; from main import app; print(json.dumps(app.openapi()))" > openapi.json
cd /path/to/my-fastapi-project
python -c "import json; from main import app; print(json.dumps(app.openapi()))" > openapi.json
2. Validate
2. 验证
speakeasy lint openapi --non-interactive -s openapi.json
speakeasy lint openapi --non-interactive -s openapi.json
3. Generate a TypeScript SDK
3. 生成TypeScript SDK
speakeasy quickstart --skip-interactive --output console
-s openapi.json
-t typescript
-n "MyApiSDK"
-p "my-api-sdk"
-s openapi.json
-t typescript
-n "MyApiSDK"
-p "my-api-sdk"
undefinedspeakeasy quickstart --skip-interactive --output console
-s openapi.json
-t typescript
-n "MyApiSDK"
-p "my-api-sdk"
-s openapi.json
-t typescript
-n "MyApiSDK"
-p "my-api-sdk"
undefinedAdding Speakeasy Extensions
添加Speakeasy扩展
After extracting a spec, add Speakeasy-specific extensions for better SDK output. These can be added in framework config or via overlay.
提取规范后,添加Speakeasy特定扩展以优化SDK输出。这些扩展可在框架配置中添加,或通过Overlay应用。
FastAPI: Add Extensions via openapi_extra
openapi_extraFastAPI: 通过openapi_extra
添加扩展
openapi_extrapython
@app.get(
"/items",
openapi_extra={
"x-speakeasy-retries": {
"strategy": "backoff",
"backoff": {"initialInterval": 500, "maxInterval": 60000, "exponent": 1.5},
"statusCodes": ["5XX", "429"]
},
"x-speakeasy-group": "items",
"x-speakeasy-name-override": "list"
}
)
def list_items(): ...python
@app.get(
"/items",
openapi_extra={
"x-speakeasy-retries": {
"strategy": "backoff",
"backoff": {"initialInterval": 500, "maxInterval": 60000, "exponent": 1.5},
"statusCodes": ["5XX", "429"]
},
"x-speakeasy-group": "items",
"x-speakeasy-name-override": "list"
}
)
def list_items(): ...Django: Add Extensions via SPECTACULAR_SETTINGS
SPECTACULAR_SETTINGSDjango: 通过SPECTACULAR_SETTINGS
添加扩展
SPECTACULAR_SETTINGSpython
undefinedpython
undefinedsettings.py
settings.py
SPECTACULAR_SETTINGS = {
# ... other settings
'EXTENSIONS_TO_SCHEMA_FUNCTION': lambda generator, request, public: {
'x-speakeasy-retries': {
'strategy': 'backoff',
'backoff': {'initialInterval': 500, 'maxInterval': 60000, 'exponent': 1.5},
'statusCodes': ['5XX']
}
}
}
undefinedSPECTACULAR_SETTINGS = {
# ... 其他设置
'EXTENSIONS_TO_SCHEMA_FUNCTION': lambda generator, request, public: {
'x-speakeasy-retries': {
'strategy': 'backoff',
'backoff': {'initialInterval': 500, 'maxInterval': 60000, 'exponent': 1.5},
'statusCodes': ['5XX']
}
}
}
undefinedSpring Boot: Add Extensions via Custom OperationCustomizer
OperationCustomizerSpring Boot: 通过自定义OperationCustomizer
添加扩展
OperationCustomizerjava
@Bean
public OperationCustomizer operationCustomizer() {
return (operation, handlerMethod) -> {
operation.addExtension("x-speakeasy-group",
handlerMethod.getBeanType().getSimpleName().replace("Controller", "").toLowerCase());
return operation;
};
}java
@Bean
public OperationCustomizer operationCustomizer() {
return (operation, handlerMethod) -> {
operation.addExtension("x-speakeasy-group",
handlerMethod.getBeanType().getSimpleName().replace("Controller", "").toLowerCase());
return operation;
};
}NestJS: Add Extensions via Decorator Options
NestJS: 通过装饰器选项添加扩展
typescript
@Get()
@ApiOperation({
summary: 'List items',
operationId: 'listItems'
})
@ApiExtension('x-speakeasy-group', 'items')
@ApiExtension('x-speakeasy-name-override', 'list')
listItems() { ... }typescript
@Get()
@ApiOperation({
summary: 'List items',
operationId: 'listItems'
})
@ApiExtension('x-speakeasy-group', 'items')
@ApiExtension('x-speakeasy-name-override', 'list')
listItems() { ... }Via Overlay (Any Framework)
通过Overlay添加(任意框架)
If you cannot modify framework code, use an overlay:
yaml
overlay: 1.0.0
info:
title: Speakeasy Extensions
version: 1.0.0
actions:
- target: $.paths['/items'].get
update:
x-speakeasy-group: items
x-speakeasy-name-override: list如果无法修改框架代码,可使用Overlay:
yaml
overlay: 1.0.0
info:
title: Speakeasy Extensions
version: 1.0.0
actions:
- target: $.paths['/items'].get
update:
x-speakeasy-group: items
x-speakeasy-name-override: listCommon Issues After Extraction
提取后常见问题
| Issue | Symptom | Fix |
|---|---|---|
| Missing operationIds | Lint warning; SDK methods get generic names | Add operationIds via overlay or use |
| Missing descriptions | Lint hints; SDK has no documentation | Add descriptions to endpoints and schemas in source code or via overlay |
| Overly permissive schemas | Schemas use | Tighten schemas in source code; use stricter validation decorators |
| No response schemas | Lint errors; SDK return types are | Add explicit response models to your framework endpoints |
| Duplicate operationIds | Lint errors; generation fails | Ensure each endpoint has a unique operationId |
| Missing authentication | No security schemes in spec | Add security metadata to your framework config or via overlay |
| 问题 | 症状 | 修复方案 |
|---|---|---|
| 缺少operationIds | 检查警告;SDK方法使用通用名称 | 通过Overlay添加operationIds,或使用 |
| 缺少描述 | 检查提示;SDK无文档 | 在源代码或Overlay中为端点和Schema添加描述 |
| Schema过于宽松 | Schema使用 | 在源代码中收紧Schema;使用更严格的验证装饰器 |
| 无响应Schema | 检查错误;SDK返回类型为 | 为框架端点添加明确的响应模型 |
| 重复的operationIds | 检查错误;生成失败 | 确保每个端点有唯一的operationId |
| 缺少认证信息 | 规范中无安全方案 | 在框架配置或Overlay中添加安全元数据 |
What NOT to Do
禁忌事项
- Do NOT hand-write an OpenAPI spec when the framework can generate one -- always extract first
- Do NOT edit the extracted spec directly -- use overlays for fixes so re-extraction does not lose changes
- Do NOT skip validation -- extracted specs often have issues that block SDK generation
- Do NOT assume the extracted spec is complete -- frameworks may omit auth, error responses, or headers
- Do NOT start the server in production mode for extraction -- use development or test configuration
- 请勿在框架可自动生成时手动编写OpenAPI规范——务必优先提取
- 请勿直接编辑提取的规范——使用Overlay进行修复,避免重新提取时丢失修改
- 请勿跳过验证步骤——提取的规范通常存在问题,会阻碍SDK生成
- 请勿假设提取的规范是完整的——框架可能会遗漏认证、错误响应或头信息
- 请勿在生产模式下启动服务器进行提取——使用开发或测试配置
Troubleshooting
故障排查
| Error | Cause | Solution |
|---|---|---|
| App dependencies not installed | Run |
| Connection refused (Spring Boot, NestJS) | Server not fully started | Increase sleep time or poll for readiness |
| Empty or minimal spec | Routes not registered at import time | Ensure all route modules are imported; check lazy loading |
| YAML parse error | Extracted file has invalid syntax | Re-extract; check for print statements polluting stdout |
| Dependencies not installed | Run |
No | springdoc not configured | Add |
No | Swagger module not set up | Configure |
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 应用依赖未安装 | 运行 |
| 连接被拒绝(Spring Boot、NestJS) | 服务器未完全启动 | 增加等待时间或轮询就绪状态 |
| 规范为空或内容极少 | 路由未在导入时注册 | 确保所有路由模块已导入;检查懒加载设置 |
| YAML解析错误 | 提取的文件语法无效 | 重新提取;检查是否有打印语句污染标准输出 |
| 依赖未安装 | 运行 |
无 | springdoc未配置 | 添加 |
无 | Swagger模块未设置 | 在 |
Related Skills
相关技能
- - Add x-speakeasy-* extensions via overlay
manage-openapi-overlays - - Generate SDK after extraction
start-new-sdk-project
- - 通过Overlay添加x-speakeasy-*扩展
manage-openapi-overlays - - 提取后生成SDK
start-new-sdk-project