7

I have a rails 6 project and am trying to document the API using swagger and the rswag gem.

My rspec spec for the controller is as follows:

require 'swagger_helper'

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

  let!(:book1) { create :book }
  let!(:book2) { create :book }
  let!( :account) { create :account }

  let!(:access_token) { Auth::JsonWebToken.encode(account_id: account.id) }
  let!(:Authorization) { access_token.to_s }

  path '/api/v1/books' do

    get('list books') do
      parameter name: :Authorization, in: :header, type: :string
      produces 'application/json'

      response(200, 'successful') do

        after do |example|
          example.metadata[:response][:content] = {
            'application/json' => {
              example: JSON.parse(response.body, symbolize_names: true)
            }
          }
        end
        run_test! do |response|
          data = JSON.parse(response.body)
          expect(data['books'].count).to eq(2)
        end
      end
    end
  end

  path '/api/v1/books/{id}' do
    parameter name: 'id', in: :path, type: :string, description: 'id'
    parameter name: :Authorization, in: :header, type: :string

    get('show book') do
      response(200, 'successful') do
        let(:id) { book1.id }

        after do |example|
          example.metadata[:response][:content] = {
            'application/json' => {
              example: JSON.parse(response.body, symbolize_names: true)
            }
          }
        end

        run_test! do |response|
          data = JSON.parse(response.body)
          expect(data['id']).to eq(book1['id'])
        end
      end
    end
  end

  path 'api/v1/books' do
    post 'Creates a book' do
      consumes 'application/json'

      parameter name: :book, in: :body, schema: {
        type: :object,
        properties: {
          title: { type: :string },
          author: { type: :string },
          publisher: { type: :string },
          editor: { type: :string }
        }
      }

      response '200', 'book created' do
        let(:book) { { title: 'New Book', author: 'New Author'}}

        after do |example|
          example.metadata[:response][:content] = {
            'application/json' => {
              example: JSON.parse(response.body, symbolize_names: true)
            }
          }
        end

        run_test! do |response|
          data = JSON.parse(response.body)
          expect(data['title']).to eq('New Book')
          new_books_in_db = Book.where(title: 'New Book').count
          expect(new_books_in_db).to eq(1)
        end
      end
    end
  end
end

The resulting swagger.json file is as follows


  "openapi": "3.0.1",
  "info": {
    "title": "API V1",
    "version": "v1"
  },
  "paths": {
    "/api/v1/books": {
      "get": {
        "summary": "list books",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "successful"
          }
        }
      }
    },
    "/api/v1/books/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "description": "id",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "Authorization",
          "in": "header",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "summary": "show book",
        "responses": {
          "200": {
            "description": "successful"
          }
        }
      }
    },
    "api/v1/books": {
      "post": {
        "summary": "Creates a book",
        "parameters": [

        ],
        "responses": {
          "200": {
            "description": "book created"
          }
        },
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "author": {
                    "type": "string"
                  },
                  "publisher": {
                    "type": "string"
                  },
                  "editor": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://{defaultHost}",
      "variables": {
        "defaultHost": {
          "default": "www.example.com"
        }
      }
    }
  ]
}

The complete code for the project is at https://github.com/marksack/rails_swagger_test (the master branch).

I have two questions/problems.

  1. I have the code for auto generating the examples included as per the rswag documentation. But the auto generate is not working. What do I need to do to get the auto generation feature workin?

  2. For our use case, we will get the most benefit if we can auto generate the schema for the request body. The rswag documentation does not indicate how to do that. How can I auto generate the schema for the request body?

UPDATE

For #1, I got it working by disabing dry run, i.e. the command needs to be SWAGGER_DRY_RUN=0 RAILS_ENV=test rails rswag instead of RAILS_ENV=test rails rswag.

For #2, I made a mistake in my question. I've updated the question above to reference the request body instead of the response body.

mark.sack
  • 89
  • 2
  • 6

1 Answers1

0

I was struggling with auto generation of responses aswell for a few weeks. However, updating the rswag gems to the latest version fixed a lot of my issues. Hopefully this helps some people out there