Techioz Blog

認証ありまたは認証なしでドキュメントを生成する rswag

概要

JWT ベアラー トークンを受け入れる API があります。予想された結果:

私の考えでは、過去に自分の認証が成功しているかどうかすらわからない API に取り組んだことがあります…このトークンに間違ったキーを使用しているのでしょうか?そこで、ユーザーに「トークンを取得しましたが、正しくありません」と知らせました。

問題は次のとおりです。rswag を使用する場合、認証トークンを送信することと認証トークンを送信しないことの両方をテストする方法がわかりません。

# frozen_string_literal: true

require 'rails_helper'

RSpec.configure do |config|
  # Specify a root folder where Swagger JSON files are generated
  # NOTE: If you're using the rswag-api to serve API descriptions, you'll need
  # to ensure that it's configured to serve Swagger from the same folder
  config.swagger_root = Rails.root.join('swagger').to_s

  # Define one or more Swagger documents and provide global metadata for each one
  # When you run the 'rswag:specs:swaggerize' rake task, the complete Swagger will
  # be generated at the provided relative path under swagger_root
  # By default, the operations defined in spec files are added to the first
  # document below. You can override this behavior by adding a swagger_doc tag to the
  # the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json'
  config.swagger_docs = {
    'v1/swagger.yaml' => {
      openapi: '3.0.1',
      info: {
        title: 'My API',
        version: 'v1'
      },
      paths: {},
      servers: [
        {
          url: 'https://{defaultHost}',
          variables: {
            defaultHost: {
              default: 'www.example.com'
            }
          }
        }
      ],
      components: {
        securitySchemes: {
          AuthToken: {
            type: :http, scheme: :bearer, bearerFormat: JWT
          }
        }
      },
      security: [ { AuthToken: [] } ]
    }
  }

  # Specify the format of the output Swagger file when running 'rswag:specs:swaggerize'.
  # The swagger_docs configuration option has the filename including format in
  # the key, this may want to be changed to avoid putting yaml in json files.
  # Defaults to json. Accepts ':json' and ':yaml'.
  config.swagger_format = :yaml
end

テスト:

RSpec.describe 'api/v1/unicorns', type: :request do

  path '/unicorns.json' do

    let(:user) { create(:perceptyx_owner) }
    let(:account) { create(:account, owners: [user]) }

    get 'retrieves a list of accessible unicorns' do
      tags 'unicorns'
      produces 'application/vnd.api+json'
      security [ {AuthToken: [], NoAuth: []} ]
      response '200', 'properly authenticated request' do
        let(:Authorization) { JWT.encode({ auth: { user_id: user.pyx_user_id } }, nil, 'none') }
        run_test!
      end

      response '400', 'malformatted auth token' do
        let(:Authorization) { 'AAABBBCCCDDDDEEE-invalid' }
        run_test!
      end

      response '401', 'no authentication' do
        # it's not clear how you would run a test that did
        # not include a bearer token header -- this tests results
        # in "undefined method `Authorization'"
 
        run_test!
      end
    end
  end
end

ここで別の securityScheme リストを使用して、アプリが無視する ApiKeyAuth のような二次認証を設定することを考えました。しかし、デフォルトではなくテストにセキュリティを設定しようとすると、それは個々の「応答」ではなく「パス」内のすべてのテストに適用されるようです。

また、「Authorization」を nil に設定しようとしました…しかし、明らかに値のないキーが送信されました。それは同じではありません。

これはできるでしょうか?どうやって?これをドキュメントで確認する段階まではまだ行っていませんが、この質問の一部ではありませんが、そこで成功するために何ができるかについてのヒントがあれば幸いです。 :)

解決策

Authorization を nil に設定してみてください。

response '401', 'no authentication' do
  let(:Authorization) { }

  run_test!
end