mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-25 07:16:40 +00:00
Merge pull request #32 from vinh0604/master
Validating response headers and setting response examples
This commit is contained in:
commit
17a6cd13c4
41
README.md
41
README.md
@ -243,6 +243,47 @@ describe 'Blogs API' do
|
||||
end
|
||||
```
|
||||
|
||||
### Response headers ###
|
||||
|
||||
In Rswag, you could use `header` method inside the response block to specify header objects for this response. Rswag will validate your response headers with those header objects and inject them into the generated swagger file:
|
||||
|
||||
```ruby
|
||||
# spec/integration/comments_spec.rb
|
||||
describe 'Blogs API' do
|
||||
|
||||
path '/blogs/{blog_id}/comments' do
|
||||
|
||||
post 'Creates a comment' do
|
||||
|
||||
response 422, 'invalid request' do
|
||||
header 'X-Rate-Limit-Limit', type: :integer, description: 'The number of allowed requests in the current period'
|
||||
header 'X-Rate-Limit-Remaining', type: :integer, description: 'The number of remaining requests in the current period'
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
### Response examples ###
|
||||
|
||||
You can provide custom response examples to the generated swagger file by calling the method `examples` inside the response block:
|
||||
|
||||
```ruby
|
||||
# spec/integration/blogs_spec.rb
|
||||
describe 'Blogs API' do
|
||||
|
||||
path '/blogs/{blog_id}' do
|
||||
|
||||
get 'Retrieves a blog' do
|
||||
|
||||
response 200, 'blog found' do
|
||||
examples 'application/json' => {
|
||||
id: 1,
|
||||
title: 'Hello world!',
|
||||
content: '...'
|
||||
}
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
### Route Prefix for Swagger JSON Endpoints ###
|
||||
|
||||
The functionality to expose Swagger files, such as those generated by rswag-specs, as JSON endpoints is implemented as a Rails Engine. As with any Engine, you can change it's mount prefix in _routes.rb_:
|
||||
|
||||
@ -61,6 +61,14 @@ module Rswag
|
||||
metadata[:response][:headers][name] = attributes
|
||||
end
|
||||
|
||||
# NOTE: Similar to 'description', 'examples' need to handle the case when
|
||||
# being invoked with no params to avoid overriding 'examples' method of
|
||||
# rspec-core ExampleGroup
|
||||
def examples(example = nil)
|
||||
return super() if example.nil?
|
||||
metadata[:response][:examples] = example
|
||||
end
|
||||
|
||||
def run_test!
|
||||
# NOTE: rspec 2.x support
|
||||
if RSPEC_VERSION < 3
|
||||
|
||||
@ -13,6 +13,7 @@ module Rswag
|
||||
|
||||
def validate!(response)
|
||||
validate_code!(response.code)
|
||||
validate_headers!(response.headers)
|
||||
validate_body!(response.body)
|
||||
end
|
||||
|
||||
@ -24,6 +25,20 @@ module Rswag
|
||||
end
|
||||
end
|
||||
|
||||
def validate_headers!(headers)
|
||||
header_schema = @api_metadata[:response][:headers]
|
||||
return if header_schema.nil?
|
||||
header_schema.each do |header_name, schema|
|
||||
validate_header!(schema, header_name, headers[header_name.to_s])
|
||||
end
|
||||
end
|
||||
|
||||
def validate_header!(schema, header_name, header_value)
|
||||
JSON::Validator.validate!(schema.merge(@global_metadata), header_value.to_json)
|
||||
rescue JSON::Schema::ValidationError => ex
|
||||
raise UnexpectedResponse, "Expected response headers #{header_name} to match schema: #{ex.message}"
|
||||
end
|
||||
|
||||
def validate_body!(body)
|
||||
response_schema = @api_metadata[:response][:schema]
|
||||
return if response_schema.nil?
|
||||
|
||||
@ -151,6 +151,25 @@ module Rswag
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#examples(example)' do
|
||||
let(:json_example) do
|
||||
{
|
||||
'application/json' => {
|
||||
foo: 'bar'
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:api_metadata) { { response: {} } }
|
||||
|
||||
before do
|
||||
subject.examples(json_example)
|
||||
end
|
||||
|
||||
it "adds to the 'response examples' metadata" do
|
||||
expect(api_metadata[:response][:examples]).to eq(json_example)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -66,6 +66,43 @@ module Rswag
|
||||
it { expect { call }.to raise_error UnexpectedResponse }
|
||||
end
|
||||
end
|
||||
|
||||
context "'headers' provided" do
|
||||
before do
|
||||
api_metadata[:response][:headers] = {
|
||||
'X-Rate-Limit-Limit' => {
|
||||
description: 'The number of allowed requests in the current period',
|
||||
type: 'integer'
|
||||
},
|
||||
'X-Rate-Limit-Remaining' => {
|
||||
description: 'The number of remaining requests in the current period',
|
||||
type: 'integer'
|
||||
},
|
||||
'X-Rate-Limit-Reset' => {
|
||||
description: 'The number of seconds left in the current period',
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'response code & body matches' do
|
||||
let(:response) { OpenStruct.new(code: 200, body: '{}', headers: {
|
||||
'X-Rate-Limit-Limit' => 1,
|
||||
'X-Rate-Limit-Remaining' => 1,
|
||||
'X-Rate-Limit-Reset' => 1
|
||||
}) }
|
||||
it { expect { call }.to_not raise_error }
|
||||
end
|
||||
|
||||
context 'response code matches & body does not' do
|
||||
let(:response) { OpenStruct.new(code: 200, body: '{}', headers: {
|
||||
'X-Rate-Limit-Limit' => 'invalid',
|
||||
'X-Rate-Limit-Remaining' => 'invalid',
|
||||
'X-Rate-Limit-Reset' => 'invalid'
|
||||
}) }
|
||||
it { expect { call }.to raise_error UnexpectedResponse }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -17,6 +17,10 @@ class BlogsController < ApplicationController
|
||||
# GET /blogs/1
|
||||
def show
|
||||
@blog = Blog.find_by_id(params[:id])
|
||||
|
||||
fresh_when(@blog)
|
||||
return unless stale?(@blog)
|
||||
|
||||
respond_with @blog, status: :not_found and return unless @blog
|
||||
respond_with @blog
|
||||
end
|
||||
|
||||
@ -50,8 +50,18 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
|
||||
produces 'application/json'
|
||||
|
||||
response '200', 'blog found' do
|
||||
header 'ETag', type: :string
|
||||
header 'Last-Modified', type: :string
|
||||
header 'Cache-Control', type: :string
|
||||
|
||||
schema '$ref' => '#/definitions/blog'
|
||||
|
||||
examples 'application/json' => {
|
||||
id: 1,
|
||||
title: 'Hello world!',
|
||||
content: 'Hello world and hello universe. Thank you all very much!!!'
|
||||
}
|
||||
|
||||
let(:blog) { Blog.create(title: 'foo', content: 'bar') }
|
||||
let(:id) { blog.id }
|
||||
run_test!
|
||||
|
||||
@ -89,8 +89,26 @@
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "blog found",
|
||||
"headers": {
|
||||
"ETag": {
|
||||
"type": "string"
|
||||
},
|
||||
"Last-Modified": {
|
||||
"type": "string"
|
||||
},
|
||||
"Cache-Control": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"$ref": "#/definitions/blog"
|
||||
},
|
||||
"examples": {
|
||||
"application/json": {
|
||||
"id": 1,
|
||||
"title": "Hello world!",
|
||||
"content": "Hello world and hello universe. Thank you all very much!!!"
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user