How to set a bearer token param for testing a Rails API using Rswag UI

5.7k Views Asked by At

I'm having issues when testing my API using the Rswag UI gem. It seems that authorization headers are not being set properly in the UI after entering the token in the param field. Nevertheless, the test itself is passing and the endpoint is being hit when I run the test in the terminal. Please take a look at the image attached below for more info.

My authenticate method in the application_controller looks like this:

def authenticate!
    authenticate_or_request_with_http_token do |token, _|
      @auth = ApiKey.exists?(access_token: token)
    end
end

The swagger_helper security definition looks like this

  securityDefinitions: {
    Bearer: {
      description: '...',
      type: :apiKey,
      name: 'Authorization',
      in: :header
    }
  }

And the test, which is passing, looks like this:

require 'swagger_helper'

RSpec.describe 'Api::V1::Events', type: :request do

  let(:access_token) { FactoryBot.create(:api_key).access_token }
  let(:Authorization) { "Bearer #{access_token}" }

  path '/v1/events' do
    post 'Creates an event' do
      tags 'Events'
      consumes 'application/json'
      security [Bearer: {}]
      parameter name: :Authorization, in: :header, type: :string
      parameter name: :event, in: :body, schema: {
          type: :object,
          properties: {
              name: { type: :string },
              description: { type: :string },
              date: { type: :string },
              time: { type: :string }
          },
          required: [ 'name', 'description', 'date', 'time' ]
      }

      response '201', 'created' do
        let(:event) { { name: 'foo', description: 'bar', date: '2020-09-24', time: '00:00:00' } }
        run_test!
      end
    end
   end
 end

This is the line I'm struggling with: parameter name: :Authorization, in: :header, type: :string I've tried different types, such as, http, string and apiKey and I haven't had luck

The Curl that Swager UI should return should look like this:

curl -X POST "http://localhost:3000/v1/events" -H "accept: */*" -H 'Authorization: Bearer ab4d77e61a5ccdc402sb75867328ea77' -H "Content-Type: application/json" -d "{\"name\":\"string\",\"description\":\"string\",\"date\":\"string\",\"time\":\"string\"}"

enter image description here

2

There are 2 best solutions below

1
On BEST ANSWER

I found a solution based on the comment I got. I was not seeing the Authorize button in the swagger UI. So I basically made some updates in the swagger_helper among other files

I changed this:

  'v1/swagger.yaml' => {
      openapi: '3.0.1',
   ...

To this

  'v1/swagger.json' => {
      swagger: '2.0',
      ....
   }

Also on the bottom of the file I changed config.swagger_format = :yaml to config.swagger_format = :json

Then I ran the following command: rswag:specs:swaggerize to generate the json file

I also made an update to the initializer from c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs' to c.swagger_endpoint '/api-docs/v1/swagger.json', 'API V1 Docs'

Finally, I restarted the server and I was able to see the above mentioned button to enter the token.

2
On

The solution of going back to the previous version works, but I want to stay with openapi: '3.0.1' and I found the solution.

Without having to change everything to json I just have to add this section:

"v1/swagger.yaml" => {
 openapi: "3.0.1",
 ...,
 components: {
  securitySchemes: {
   Bearer: {
    type: :apiKey,
    name: 'Authorization',
    in: :header,
    description: 'Your Bearer token'
   }
  }
 }
}

We keep the property security [Bearer: {}] in the rspec file:

require 'swagger_helper'

RSpec.describe 'Api::V1::Events', type: :request do

  let(:access_token) { FactoryBot.create(:api_key).access_token }
  let(:Authorization) { "Bearer #{access_token}" }

  path '/v1/events' do
    post 'Creates an event' do
      tags 'Events'
      consumes 'application/json'
      # /////
      security [Bearer: {}]
      # /////
      parameter name: :Authorization, in: :header, type: :string
      parameter name: :event, in: :body, schema: {
          type: :object,
          properties: {
              name: { type: :string },
              description: { type: :string },
              date: { type: :string },
              time: { type: :string }
          },
          required: [ 'name', 'description', 'date', 'time' ]
      }

      response '201', 'created' do
        let(:event) { { name: 'foo', description: 'bar', date: '2020-09-24', time: '00:00:00' } }
        run_test!
      end
    end
   end
 end

This will display the "Authorize" button: Authorize button

Then a modal will appear where you can load the token you want and that's it. Authorize modal