在许多文件中拆分 swagger 定义
Posted
技术标签:
【中文标题】在许多文件中拆分 swagger 定义【英文标题】:splitting swagger definition across many files 【发布时间】:2016-06-03 19:18:00 【问题描述】:问题:如何跨文件拆分 swagger 定义?该领域有哪些可能性?问题详情如下:
我想要的示例 - 在 RAML 中
我确实有 RAML 方面的经验,我所做的是,例如:
/settings:
description: |
This resource defines application & components configuration
get:
is: [ includingCustomHeaders ]
description: |
Fetch entire configuration
responses:
200:
body:
example: !include samples/settings.json
schema: !include schemas/settings.json
最后两行在这里很重要 - 带有!include <filepath>
的那些 - 在 RAML 中,我可以将整个合同拆分为许多文件,这些文件只是被 RAML 解析器动态包含(并且所有基于 RAML 的工具都使用 RAML 解析器) )。
我从中得到的好处是:
我的合同更清晰,更易于维护,因为架构不是内联的 但这真的很重要:我可以在其他工具中重复使用架构文件来执行验证、模拟生成、存根、生成测试等。换句话说,通过这种方式,我可以在合约(RAML,本例)和其他工具(非 RAML,非 swagger,仅基于 JSONschema 的工具)中重用架构文件。回到 Swagger
据我所知,swagger 支持$ref
关键字,它允许加载外部文件。但是这些文件是通过 HTTP/AJAX 获取的还是只是本地文件?
是整个规范都支持它,还是只是一些工具支持它而一些不支持?
我发现here 是swagger 的输入必须是一个文件。这对于大型项目来说非常不方便:
因为大小 而且因为如果我想使用一些不招摇的东西,我就不能重用架构或者,换句话说,我可以使用 swagger 实现与 RAML 相同的效果吗?就拆分文件而言?
【问题讨论】:
【参考方案1】:The specification 允许在多个位置引用,但不允许在任何地方引用。这些引用的解析取决于规范的托管位置以及您要执行的操作。
对于渲染动态用户界面之类的事情,是的,您确实需要最终将整个定义加载到可能由许多文件组成的“单个对象”中。如果执行代码生成,则可以直接从文件系统加载定义。但最终还是有 swagger 解析器在做解析,这在 Swagger 中比其他定义格式更细粒度和可控。
在您的情况下,您将使用指向架构引用的 JSON 指针:
responses:
200:
description: the response
schema:
通过本地参考
$ref: '#/definitions/myModel'
通过绝对引用:
$ref: 'http://path/to/your/resource'
通过相对引用,这将是“相对于加载此文档的位置”
$ref: 'resource.json#/myModel
通过内联定义
type: object
properties:
id:
type: string
【讨论】:
我喜欢你的回答,但我错过了一件事——我不知道我将使用哪些确切的工具来完成某些工作,例如用于生成文档。如果我拆分文件并且我想要的工具需要一个文件,我该怎么办?是否有任何推荐/标准的方法将 (build) 一个大张旗鼓的多文件定义合并为一个,以便我在我的存储库中保留单独的文件 + 我可以动态构建单个文件? 这是一个很好的问题。正如人们所猜测的那样,那里有 很多 工具,并且它们对 swagger 规范有不同程度的支持。如果你使用官方的 swagger-api OSS 工具,那么缺乏对规范的支持是一个缺陷,将被修复。拆分规范的机制实际上取决于业务需求,因此目前不是很标准。使用包括 (swaggerhub) 在内的工具,将很快形成标准实践,因为这些工具将促进整个过程。【参考方案2】:当我使用引用拆分 OpenAPI V3 文件时,我尽量避免 sock drawer 反模式,而是对 YAML 文件使用功能分组。
我还让每个 YAML 文件本身都是有效的 OpenAPI V3 规范。
我从openapi.yaml
文件开始。
openapi: 3.0.3
info:
title: MyAPI
description: |
This is the public API for my stuff.
version: "3"
tags:
# NOTE: the name is needed as the info block uses `title` rather than name
- name: Authentication
$ref: 'authn.yaml#/info'
paths:
# NOTE: here are the references to the other OpenAPI files
# from the path. Note because OpenAPI requires paths to
# start with `/` and that is already used as a separator
# replace the `/` with `%2F` for the path reference.
'/authn/start':
$ref: 'authn.yaml#/paths/%2Fstart'
然后在功能组中:
openapi: 3.0.3
info:
title: Authentication
description: |
This is the authentication module.
version: "3"
paths:
# NOTE: don't include the `/authn` prefix here that top level grouping is
# in the `openapi.yaml` file.
'/start':
get:
responses:
"200":
description: OK
通过这种分离,您可以单独测试每个文件或作为一个组来测试整个 API。
您可能会在某些地方重复自己,但这样做可以限制在使用“通用”库时对其他 API 端点进行破坏性更改的机会。
但是,您仍然应该有一些通用定义库,例如:
错误 安全这种方法有一个限制,那就是“鉴别器”(虽然它可能是一个 ReDoc 问题,但如果您的类型在 openapi.yaml
之外有鉴别器,则 ReDoc 无法正确呈现。
【讨论】:
【参考方案3】:有关如何将 Swagger 文档拆分为多个文件的详细信息,请参阅 this answer。这是使用 JSON 完成的,但同样的概念也适用于 RAML。
编辑:在此处添加链接内容
Swagger JSON 的基本结构应如下所示:
"swagger": "2.0",
"info":
"title": "",
"version": "version number here"
,
"basePath": "/",
"host": "host goes here",
"schemes": [
"http"
],
"produces": [
"application/json"
],
"paths": ,
"definitions":
paths
和 definitions
是您需要插入 API 支持的路径和描述响应对象的模型定义的地方。您可以动态填充这些对象。一种方法是为每个实体的路径和模型创建一个单独的文件。
假设您的 API 中的一个对象是“汽车”。
路径:
"paths":
"/cars":
"get":
"tags": [
"Car"
],
"summary": "Get all cars",
"description": "Returns all of the cars.",
"responses":
"200":
"description": "An array of cars",
"schema":
"type": "array",
"items":
"$ref": "#/definitions/car"
,
"404":
"description": "error fetching cars",
"schema":
"$ref": "#/definitions/error"
型号:
"car":
"properties":
"_id":
"type": "string",
"description": "car unique identifier"
,
"make":
"type": "string",
"description": "Make of the car"
,
"model":
"type": "string",
"description": "Model of the car."
然后,您可以将它们中的每一个放在自己的文件中。当您启动服务器时,您可以获取这两个 JSON 对象,并将它们附加到基本 swagger 对象(paths
或 definitions
)中的适当对象,并将该基本对象作为您的 Swagger JSON 对象。
您还可以通过仅在服务器启动时执行一次附加来进一步优化这一点(因为 API 文档在服务器运行时不会更改)。然后,当点击“serve Swagger docs”端点时,您可以只返回您在服务器启动时创建的缓存 Swagger JSON 对象。
可以通过捕获对/api-docs
的请求来拦截“serve Swagger docs”端点,如下所示:
app.get('/api-docs', function(req, res)
// return the created Swagger JSON object here
);
【讨论】:
我没有投反对票。但是,我在链接中的回复中缺少的是如何加载外部参考(本地文件),例如"$ref": "#/definitions/car"
?它是由 swagger 支持还是必须手动完成?以及如何手动将文件包含到最终招摇中?老实说,我知道我可以手动完成所有操作,但我正在寻找标准解决方案。
$ref": "#/definitions/car
不是文件,它是模型对象。因此,您需要在 swagger 对象的“模型”中定义汽车模型。您可以将“汽车”模型的定义包含在另一个文件中,但最后必须将其加载到从 /api-docs
端点提供的 swagger 文件中。【参考方案4】:
您可以使用 $ref 但灵活性不高,我建议您使用外部工具(例如“Yamlinc”)使用“$include”标签将多个文件混合为一个来处理 YAML。
阅读更多:https://github.com/javanile/yamlinc
【讨论】:
以上是关于在许多文件中拆分 swagger 定义的主要内容,如果未能解决你的问题,请参考以下文章
swagger codegen 在生成的文件中覆盖我的自定义代码