在许多文件中拆分 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": 

pathsdefinitions 是您需要插入 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 对象(pathsdefinitions)中的适当对象,并将该基本对象作为您的 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 中的 $ref 标签

swagger codegen 在生成的文件中覆盖我的自定义代码

在.net core web api中添加自定义属性到OpenAPI规范文件和swagger

leadtools20,从多个图像创建多页文件

leadtools20,从多个图像创建多页文件

springBoot整合Swagger2