Initial commit for trying to produce and consume v3 swagger

This commit is contained in:
Jay Danielian 2019-06-29 18:12:21 -04:00
parent 10bb732148
commit 768a1a1d43
10 changed files with 130 additions and 91 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@
**/*/node_modules
*.swp
Gemfile.lock
/.idea/

View File

@ -1 +1 @@
2.3.1
2.5.1

View File

@ -13,7 +13,7 @@ when '4', '5'
gem 'responders'
end
gem 'sqlite3'
gem 'sqlite3', '~> 1.3.6'
gem 'rswag-api', path: './rswag-api'
gem 'rswag-ui', path: './rswag-ui'

View File

@ -35,6 +35,14 @@ module Rswag
end
end
#TODO: look at adding request_body method to handle diffs in Open API 2.0 to 3.0
# https://swagger.io/docs/specification/describing-request-body/
# need to make sure we output requestBody in the swagger generator .json
# also need to make sure that it can handle content: , required: true/false, schema: ref
def parameter(attributes)
if attributes[:in] && attributes[:in].to_sym == :path
attributes[:required] = true

View File

@ -15,7 +15,7 @@ module Rswag
class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute
def self.validate(current_schema, data, fragments, processor, validator, options={})
return if data.nil? && current_schema.schema['x-nullable'] == true
return if data.nil? && (current_schema.schema['nullable'] == true || current_schema.schema['x-nullable'] == true)
super
end
end

View File

@ -39,7 +39,7 @@ module Rswag
def derive_security_params(metadata, swagger_doc)
requirements = metadata[:operation][:security] || swagger_doc[:security] || []
scheme_names = requirements.flat_map { |r| r.keys }
schemes = (swagger_doc[:securityDefinitions] || {}).slice(*scheme_names).values
schemes = (swagger_doc[:components][:securitySchemes] || {}).slice(*scheme_names).values
schemes.map do |scheme|
param = (scheme[:type] == :apiKey) ? scheme.slice(:name, :in) : { name: 'Authorization', in: :header }

View File

@ -41,9 +41,12 @@ module Rswag
response_schema = metadata[:response][:schema]
return if response_schema.nil?
components_schemas = {components: {schemas: swagger_doc[:components][:schemas]}}
validation_schema = response_schema
.merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema')
.merge(swagger_doc.slice(:definitions))
.merge(components_schemas)
errors = JSON::Validator.fully_validate(validation_schema, body)
raise UnexpectedResponse, "Expected response body to match schema: #{errors[0]}" if errors.any?
end

View File

@ -10,7 +10,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
operationId 'createBlog'
consumes 'application/json'
produces 'application/json'
parameter name: :blog, in: :body, schema: { '$ref' => '#/definitions/blog' }
parameter name: :blog, in: :body, schema: { '$ref' => '#/components/schemas/blog' }
let(:blog) { { title: 'foo', content: 'bar' } }
@ -19,7 +19,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
end
response '422', 'invalid request' do
schema '$ref' => '#/definitions/errors_object'
schema '$ref' => '#/components/schemas/errors_object'
let(:blog) { { title: 'foo' } }
run_test! do |response|
@ -38,7 +38,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
let(:keywords) { 'foo bar' }
response '200', 'success' do
schema type: 'array', items: { '$ref' => '#/definitions/blog' }
schema type: 'array', items: { '$ref' => '#/components/schemas/blog' }
end
response '406', 'unsupported accept header' do
@ -65,7 +65,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
header 'Last-Modified', type: :string
header 'Cache-Control', type: :string
schema '$ref' => '#/definitions/blog'
schema '$ref' => '#/components/schemas/blog'
examples 'application/json' => {
id: 1,

View File

@ -14,17 +14,29 @@ RSpec.configure do |config|
# the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json'
config.swagger_docs = {
'v1/swagger.json' => {
swagger: '2.0',
openapi: '3.0.0',
info: {
title: 'API V1',
version: 'v1'
},
paths: {},
definitions: {
servers: [
{
url: "https://{defaultHost}",
variables: {
defaultHost: {
default: "www.example.com"
}
}
}
],
components: {
schemas: {
errors_object: {
type: 'object',
properties: {
errors: { '$ref' => '#/definitions/errors_map' }
errors: { '$ref' => '#/components/schemas/errors_map' }
}
},
errors_map: {
@ -39,15 +51,16 @@ RSpec.configure do |config|
properties: {
id: { type: 'integer' },
title: { type: 'string' },
content: { type: 'string', 'x-nullable': true },
content: { type: 'string', nullable: true },
thumbnail: { type: 'string'}
},
required: [ 'id', 'title', 'content', 'thumbnail' ]
}
},
securityDefinitions: {
securitySchemes: {
basic_auth: {
type: :basic
type: :http,
scheme: :basic
},
api_key: {
type: :apiKey,
@ -55,6 +68,7 @@ RSpec.configure do |config|
in: :query
}
}
},
}
}
end

View File

@ -1,5 +1,5 @@
{
"swagger": "2.0",
"openapi": "3.0.0",
"info": {
"title": "API V1",
"version": "v1"
@ -99,7 +99,7 @@
"name": "blog",
"in": "body",
"schema": {
"$ref": "#/definitions/blog"
"$ref": "#/components/schemas/blog"
}
}
],
@ -110,7 +110,7 @@
"422": {
"description": "invalid request",
"schema": {
"$ref": "#/definitions/errors_object"
"$ref": "#/components/schemas/errors_object"
}
}
}
@ -173,7 +173,7 @@
}
},
"schema": {
"$ref": "#/definitions/blog"
"$ref": "#/components/schemas/blog"
},
"examples": {
"application/json": {
@ -225,12 +225,23 @@
}
}
},
"definitions": {
"servers": [
{
"url": "https://{defaultHost}",
"variables": {
"defaultHost": {
"default": "www.example.com"
}
}
}
],
"components": {
"schemas": {
"errors_object": {
"type": "object",
"properties": {
"errors": {
"$ref": "#/definitions/errors_map"
"$ref": "#/components/schemas/errors_map"
}
}
},
@ -254,7 +265,7 @@
},
"content": {
"type": "string",
"x-nullable": true
"nullable": true
},
"thumbnail": {
"type": "string"
@ -268,9 +279,10 @@
]
}
},
"securityDefinitions": {
"securitySchemes": {
"basic_auth": {
"type": "basic"
"type": "http",
"scheme": "basic"
},
"api_key": {
"type": "apiKey",
@ -278,4 +290,5 @@
"in": "query"
}
}
}
}