Rswag::Helpers
This gem adds some helper methods, custom rspec matchers and predefined security schemes to make Rswag specs DRY and more readable.
- Create a helper method to remove redundant Enable auto generation examples from responses. So this code
get('list posts') do
response(200, 'successful') do
after do |example|
example.[:response][:content] = {
'application/json' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end
run_test!
end
end
can be replaced by
get('list posts') do
response(200, 'successful') do
run_test_and_generate_example!
end
end
- Provides ability to define schemas in separate files - explained below
- Adds a bunch of custom rspec matchers for better readability
- Provides ability to use some predefined security schemes
- Provides a helper method
define_tagsto replace the repetitive tag definition withsecurity scheme,consumesandproduces
'Post'
security [bearer_auth: []]
consumes 'application/json'
produces 'application/json'
can be replaced by
'Posts'
# more customization
'Posts', consumes: 'multipart/form-data'
- Provides a helper method
schema_refwhich can take a string argument to replace declarative schema reference
schema '$ref' => '#/components/schemas/Something'
# can be replace by
schema_ref 'Something'
schema anyOf: [{ '$ref' => '#/components/schemas/Something' }, { '$ref' => '#/components/schemas/SomethingElse' }]
# can be replaced by
schema_ref anyOf: ['Something', 'SomethingElse']
schema oneOf: [{ '$ref' => '#/components/schemas/Something' }, { '$ref' => '#/components/schemas/SomethingElse' }]
# can be replaced by
schema_ref oneOf: ['Something', 'SomethingElse']
schema allOf: [{ '$ref' => '#/components/schemas/Something' }, { '$ref' => '#/components/schemas/SomethingElse' }]
# can be replaced by
schema_ref allOf: ['Something', 'SomethingElse']
- Provides another helper method
schema_optionto make the schema declaration for a request short (trivial, but still less code)
parameter name: :payload, in: :body, schema: { '$ref' => '#/components/schemas/Something' }
# can be replaced by
parameter name: :payload, in: :body, schema: schema_option('Something')
Installation
Add this line to your application's Gemfile:
gem 'rswag-helpers'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install rswag-helpers
Usage
Install the gem:
$ rails g rswag:helpers:install
This will
- Create a folder
spec/schemasand also create a filespec/schemas/baseinside that folder - Modify the
spec/swagger_helper.rbfile to include the custom rspec matchers and rswag helpers
# spec/swagger_helper.rb
# loads all the defined schema files
require_relative 'schemas/base'
# Change to :api_key/:http_basic in case those are being used
# Can also provide multiple defaults like: [:bearer_jwt, :api_key]
# Can provide custom security scheme like: Rswag::Helpers::SecurityScheme.additional = { accept: {...}}
Rswag::Helpers::SecurityScheme.defaults = :bearer_jwt
- Provide predefined ways to define the security schemes like :bearer_jwt, :basic_http, :api_key
- Also provides options to add additional security schemes, example:
# spec/swagger_helper.rb
Rswag::Helpers::SecurityScheme.defaults = :bearer_jwt
Rswag::Helpers::SecurityScheme.additional = {
accept: {
description: "Use application/[custom]; version=1",
type: :apiKey,
name: 'Accept',
in: :header
}
}
spec/schemas folder
Keeping all the schemas in the spec/swagger_helper.rb can make the file very long and tough to maintain. It would be better
if we can keep the schemas in multiple files. This gem does the setup for that, and creates the spec/schemas folder for that purpose. Now other schema files can reside inside that, and can be auto loaded to be used from spec/swagger_helper.rb
Example schema:
# spec/schemas/post.rb
class Schemas::Post < Schemas::Base
class << self
def schema
@schema ||= {
type: :object,
properties: {
data: {
type: :object,
properties: {
title: { type: :string, default: 'Cheese Bacon sandwich' },
description: { type: :test, default: 'A great breakfast recipe!' },
}
}
}
}
end
end
end
And use it:
# spec/swagger_helper.rb
config.swagger_docs = {
'v1/swagger.yaml' => {
openapi: '3.0.3',
info: {
title: 'API Docs',
version: 'v1'
},
components: {
securitySchemes: Rswag::Helpers::SecurityScheme.get,
schemas: {
Post: Schemas::Post.schema,
},
security: Rswag::Helpers::SecurityScheme.security,
paths: {},
servers: []
}
}
}
These schema files are a subclass of Schemas::Base class for the purpose of loading a single file from the spec/swagger_helper.rb. Also, Schemas::Base is a subclass of Rswag::Helpers::Schema class present in the gem, which provides handy request_body method to extract the default values from the schema and construct the
request body of POST/PUT requests. For an example:
post('create post') do
'Post'
parameter name: :body, in: :body, schema: { '$ref' => '#/components/schemas/Post' }, required: true
# request_body method is present in the gem
let(:post_request_body) { Schemas::Post.request_body.deep_dup }
response(200, 'successful') do
let(:body) { post_request_body }
run_test_and_generate_example! do |response|
response_body = parsed_response(response, key: nil)
expect(response_body['data']['attributes']).to have_keys('title', 'description')
end
end
end
### Generate a schema
$ rails g rswag:schema ResourceName
Generates spec/schemas/resource_name.rb with the code:
module Schemas
class ResourceName < Base
class << self
def schema
@schema ||= {
type: :object,
properties: {
}
}
end
end
end
end