如何基于swagger.json生成curl、GO、Node.js、Java格式的API请求代码
基于swagger.json生成多语言接口请求代码的落地方案
核心实现逻辑
- 首先完成swagger/OpenAPI规范的结构解析,提取接口全量字段:包括服务根地址、接口路径、请求方法、各类参数(path路径参数、query查询参数、header请求头、body请求体)、请求内容类型、示例值等
- 预先定义4种目标语言的请求代码模板,预留通用占位符(如请求地址、请求头、请求体、方法名等),无需硬编码逻辑
- 将解析得到的结构化接口参数,适配后填充到对应模板的占位符中,自动完成代码渲染
- 做异常兼容处理,覆盖swagger定义不完整、多版本规范差异等边界场景
具体实现步骤
1. 依赖选择
优先选择成熟的解析和模板渲染工具,避免手写schema校验和字符串拼接逻辑,可根据技术栈二选一:
- Python技术栈:用
openapi-spec-validator做swagger合法性校验&结构解析,兼容OpenAPI2.0/3.0版本,用jinja2做模板渲染 - Node.js技术栈:用
swagger-parser做swagger解析,用handlebars/ejs做模板渲染
2. 核心解析逻辑示例(Python版)
from openapi_spec_validator import validate_spec from openapi_spec_validator.readers import read_from_filename import json # 读取并校验swagger文件合法性 spec_dict, _ = read_from_filename("swagger.json") validate_spec(spec_dict) # 提取全局配置 base_url = "" if "openapi" in spec_dict and spec_dict["openapi"].startswith("3"): # OpenAPI3.0 取servers配置 base_url = spec_dict.get("servers", [{"url": ""}])[0].get("url", "") else: # Swagger2.0 取basePath + host + schemes host = spec_dict.get("host", "") base_path = spec_dict.get("basePath", "") schemes = spec_dict.get("schemes", ["http"])[0] base_url = f"{schemes}://{host}{base_path}" paths = spec_dict.get("paths", {}) api_list = [] # 遍历所有接口提取结构化信息 for path, path_info in paths.items(): for method, op_info in path_info.items(): # 过滤非请求方法字段 if method not in ["get", "post", "put", "delete", "patch", "head", "options"]: continue # 提取接口基础信息 api_item = { "name": op_info.get("summary", f"{method}_{path.replace('/', '_')}"), "method": method, "path": path, "path_params": [], "query_params": [], "header_params": [], "body": None, "content_type": "application/json" } # 拆分各类参数 for param in op_info.get("parameters", []): param_type = param.get("in") if param_type == "path": api_item["path_params"].append(param) elif param_type == "query": api_item["query_params"].append(param) elif param_type == "header": api_item["header_params"].append(param) # 提取请求体 if "requestBody" in op_info: content = op_info["requestBody"].get("content", {}) # 优先取json格式的请求体 if "application/json" in content: api_item["content_type"] = "application/json" api_item["body"] = content["application/json"].get("example", {}) # 拼接完整请求地址,替换路径参数占位符 full_path = path for p in api_item["path_params"]: full_path = full_path.replace(f"{{{p['name']}}}", str(p.get("example", "test_value"))) # 拼接query参数 if api_item["query_params"]: query_str = "&".join([f"{p['name']}={p.get('example', 'test_value')}" for p in api_item["query_params"]]) full_path += f"?{query_str}" api_item["full_url"] = f"{base_url}{full_path}" api_list.append(api_item)
解析后得到的api_list就是标准化的接口结构化数据,可直接用于后续模板渲染。
3. 多语言模板示例(jinja2语法)
所有模板统一使用解析得到的api_item字段填充,修改模板即可调整生成代码的格式,无需改动解析逻辑。
3.1 Curl模板
curl -X {{api_item.method|upper}} \ {% for header in api_item.header_params %} -H '{{header.name}}: {{header.get("example", "test_value")}}' \ {% endfor %} -H 'Content-Type: {{api_item.content_type}}' \ {% if api_item.body %} -d '{{api_item.body|tojson}}' \ {% endif %} '{{api_item.full_url}}'
3.2 Go代码模板(基于net/http)
package main import ( "fmt" "net/http" "io/ioutil" "strings" ) func main() { url := "{{api_item.full_url}}" {% if api_item.body %}payload := strings.NewReader(`{{api_item.body|tojson}}`){% else %}payload := nil{% endif %} req, err := http.NewRequest("{{api_item.method|upper}}", url, payload) if err != nil { panic(err) } {% for header in api_item.header_params %}req.Header.Add("{{header.name}}", "{{header.get('example', 'test_value')}}") {% endfor %} req.Header.Add("Content-Type", "{{api_item.content_type}}") client := &http.Client{} res, err := client.Do(req) if err != nil { panic(err) } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { panic(err) } fmt.Println(string(body)) }
3.3 Node.js代码模板(基于axios)
const axios = require('axios'); async function {{api_item.name.replace(/\s+/g, '_').toLowerCase()}}() { const config = { method: '{{api_item.method}}', url: '{{api_item.full_url}}', headers: { {% for header in api_item.header_params %}'{{header.name}}': '{{header.get('example', 'test_value')}}', {% endfor %} 'Content-Type': '{{api_item.content_type}}' }{% if api_item.body %}, data: {{api_item.body|tojson}}{% endif %} }; const res = await axios(config); console.log(res.data); } {{api_item.name.replace(/\s+/g, '_').toLowerCase()}}();
3.4 Java代码模板(基于JDK11+原生HttpClient)
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class {{api_item.name.replace(/\s+/g, '')|capitalize}} { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); HttpRequest.Builder builder = HttpRequest.newBuilder() .uri(URI.create("{{api_item.full_url}}")); // 填充请求头 {% for header in api_item.header_params %}builder.header("{{header.name}}", "{{header.get('example', 'test_value')}}"); {% endfor %} builder.header("Content-Type", "{{api_item.content_type}}"); // 填充请求方法&请求体 {% if api_item.method|upper == 'GET' %}builder.GET(); {% elif api_item.body %}builder.{{api_item.method|upper}}(HttpRequest.BodyPublishers.ofString("{{api_item.body|tojson|escapejs}}")); {% else %}builder.{{api_item.method|upper}}(HttpRequest.BodyPublishers.noBody()); {% endif %} HttpRequest request = builder.build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } }
4. 代码渲染输出
将每个接口的api_item对象传入对应模板渲染后,可按需求输出:
- 每个接口单独生成4个代码文件,按语言分类存放
- 统一生成一个Markdown文档,每个接口下挂载4种语言的代码块,方便查阅
可选优化点
- 自动填充参数示例值:优先取swagger中定义的
example字段,无定义时按参数类型生成默认值(string类型填"demo",number类型填1,boolean类型填true) - 支持批量导出:可添加命令行参数,自定义swagger文件路径、输出目录、需要生成的语言类型
- 兼容特殊场景:支持form-data、x-www-form-urlencoded等非json格式的请求体生成
内容的提问来源于stack exchange,提问作者pallavi
相关产品推荐
相关产品推荐

