4

我的目标是使用带有 rswag-ui 的 rspec_api_documentation 或通过将 swagger-ui 直接添加到项目中来显示参数和响应的多个示例。我在使用我的配置生成正确的 open_api.json 时遇到了一些问题,我想知道我做错了什么。

宝石:

用于测试的 rspec_api_documentation 配置:

# spec/acceptance_helper.rb
require 'spec_helper'
require 'rspec_api_documentation'
require 'rspec_api_documentation/dsl'

RspecApiDocumentation.configure do |config|
  config.app = Rails.application

  config.api_name = 'My API'
  config.api_explanation = 'API Description'

  config.configurations_dir = Rails.root.join('public', 'docs', 'api', 'config')
  config.docs_dir = Rails.root.join('public', 'docs', 'api', 'generated')

  config.format = :open_api

  API_VERSIONS.each do |version|
    config.define_group(version) do |config|
      config.docs_dir = Rails.root.join('public', 'docs', 'api', 'generated', version.to_s)
    end
  end

  config.client_method = :client

  config.io_docs_protocol = 'https'

  config.request_headers_to_include = nil
  config.request_body_formatter = :json

  config.response_headers_to_include = []
  config.response_body_formatter = Proc.new { |response_content_type, response_body|
    response_body
  }
end

OpenAPI 配置:

swagger: '2.0'
info:
  title: My Api
  description: Blah.
  termsOfService: 'http://open-api.io/terms/'
  contact:
    name: API Support
    url: 'http://www.open-api.io/support'
    email: support@domain.com
  license:
    name: Apache 2.0
    url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
  version: 1.0.0
host: 'localhost:3000'
schemes:
  - http
  - https
consumes:
  - application/json
produces:
  - application/json

示例测试:

require 'documentation_helper'

resource 'Sessions' do
  header 'Accept', 'application/json'
  header 'Content-Type', 'application/json'

  explanation 'Endpoints to start and end API sessions for a user'

  route '/api/v1/users/sign_in', 'Sign In' do
    route_summary 'Starts a new session for a user'
    route_description 'Given valid credentials, will create a new API session for a user'

    post 'Signing in a user', document: :v1  do
      let(:user) { FactoryBot.create(:user) }

      parameter :login, 'The username or email of the user', scope: :user, required: true
      parameter :password, 'The password for the user', scope: :user, required: true

      example '401 - No user object', document: :v1 do
        request = { login: user.email, password: user.password }

        do_request(request)

        expect(status).to eq(401)
        expect(json.keys.size).to eq(1)
        expect(json['error']).to eq(I18n.t('devise.failure.unauthenticated'))
      end

      example '401 - No login', document: :v1 do
        request = { user: { password: user.password } }

        do_request(request)

        expect(status).to eq(401)
        expect(json.keys.size).to eq(1)
        expect(json['error']).to eq(I18n.t('devise.failure.unauthenticated'))
      end
    end
  end
end

生成的输出:

{
  "swagger": "2.0",
  "info": {
    "title": "My Api",
    "description": "Blah.",
    "termsOfService": "http://open-api.io/terms/",
    "contact": {
      "name": "API Support",
      "url": "http://www.open-api.io/support",
      "email": "support@domain.com"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "version": "1.0.0"
  },
  "host": "localhost:3000",
  "schemes": [
    "http",
    "https"
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/api/v1/users/sign_in": {
      "post": {
        "tags": [
          "Sessions"
        ],
        "summary": "Starts a new session for a user",
        "description": "Given valid credentials, will create a new API session for a user",
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "description": "",
            "required": false,
            "schema": {
              "type": "object",
              "properties": {
                "user": {
                  "type": "object",
                  "properties": {
                    "login": {
                      "type": "string",
                      "description": "The username or email of the user"
                    },
                    "password": {
                      "type": "string",
                      "description": "The password for the user"
                    }
                  },
                  "required": [
                    "login",
                    "password"
                  ]
                }
              }
            }
          }
        ],
        "responses": {
          "401": {
            "description": "No login",
            "schema": {
              "type": "object",
              "properties": {
              }
            },
            "headers": {
            },
            "examples": {
              "application/json": {
                "error": "You need to sign in or sign up before continuing."
              }
            }
          }
        },
        "deprecated": false,
        "security": [

        ]
      }
    }
  },
  "tags": [
    {
      "name": "Sessions",
      "description": "Endpoints to start and end API sessions for a user"
    }
  ]
}

在此处输入图像描述 期望的输出(至少我认为):

{
  "swagger": "2.0",
  "info": {
    "title": "My Api",
    "description": "Blah.",
    "termsOfService": "http://open-api.io/terms/",
    "contact": {
      "name": "API Support",
      "url": "http://www.open-api.io/support",
      "email": "support@domain.com"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "version": "1.0.0"
  },
  "host": "localhost:3000",
  "schemes": [
    "http",
    "https"
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/api/v1/users/sign_in": {
      "post": {
        "tags": [
          "Sessions"
        ],
        "summary": "Starts a new session for a user",
        "description": "Given valid credentials, will create a new API session for a user",
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "body",
            "in": "body",
            "description": "",
            "required": false,
            "schema": {
              "type": "object",
              "properties": {
                "user": {
                  "type": "object",
                  "properties": {
                    "login": {
                      "type": "string",
                      "description": "The username or email of the user"
                    },
                    "password": {
                      "type": "string",
                      "description": "The password for the user"
                    }
                  },
                  "required": [
                    "login",
                    "password"
                  ]
                }
              }
            }
          }
        ],
        "responses": {
          "401": {
            "description": "Invalid params",
            "schema": {
              "type": "object",
              "properties": {
              }
            },
            "headers": {
            },
            "examples": {
              "No password": {
                "error": "You need to sign in or sign up before continuing."
              },
              "No login": {
                "error": "You need to sign in or sign up before continuing."
              }
            }
          }
        },
        "deprecated": false,
        "security": [

        ]
      }
    }
  },
  "tags": [
    {
      "name": "Sessions",
      "description": "Endpoints to start and end API sessions for a user"
    }
  ]
}

在此处输入图像描述

4

1 回答 1

2

对不起,我迟到了一年,但我自己也遇到了。我目前正在尝试通过使用 swagger-codegen 将 open_api 输出转换为 open_api v3 将我们的文档连接到邮递员。

在浏览了 rspec_api_documentation 的代码之后,看起来它使用哈希作为构建文档的类型,并且它使用的键依赖于path+ http_method。因此,如果您尝试拥有多个使用相同密钥但具有不同有效负载的示例,那么它将采用第一个示例:https ://github.com/zipmark/rspec_api_documentation/blob/d3892cc7388460a98476734963face5a7a2ac158/lib/rspec_api_documentation /open_api/node.rb#L65

我解决此问题的方法是将虚拟查询参数传递给路径以生成唯一键。例子:

        post "/api/v2/foos?example=example1" do
          example "example1" do
            do_request(payload1)
          end
        end

        post "/api/v2/foos?example=example2" do
          example "example2" do
            do_request(payload2)
          end
        end

这并不完全理想,因为我宁愿将这些示例组合在同一个请求下,但它至少让我得到了我想要的文档(减去虚拟参数)。

希望此解决方法有所帮助。如果我找到一种方法来提交补丁以便附加而不是跳过示例,我将发布一个指向 PR 的链接。

于 2021-05-23T22:08:32.290 回答