mirror of
https://github.com/ditkrg/rswag.git
synced 2026-01-22 22:06:43 +00:00
Initial commit for trying to produce and consume v3 swagger
This commit is contained in:
parent
10bb732148
commit
768a1a1d43
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@
|
||||
**/*/node_modules
|
||||
*.swp
|
||||
Gemfile.lock
|
||||
/.idea/
|
||||
|
||||
@ -1 +1 @@
|
||||
2.3.1
|
||||
2.5.1
|
||||
|
||||
2
Gemfile
2
Gemfile
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 }
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -14,47 +14,61 @@ 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: {
|
||||
errors_object: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
errors: { '$ref' => '#/definitions/errors_map' }
|
||||
servers: [
|
||||
{
|
||||
url: "https://{defaultHost}",
|
||||
variables: {
|
||||
defaultHost: {
|
||||
default: "www.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
components: {
|
||||
schemas: {
|
||||
errors_object: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
errors: { '$ref' => '#/components/schemas/errors_map' }
|
||||
}
|
||||
},
|
||||
errors_map: {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
},
|
||||
blog: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
title: { type: 'string' },
|
||||
content: { type: 'string', nullable: true },
|
||||
thumbnail: { type: 'string'}
|
||||
},
|
||||
required: [ 'id', 'title', 'content', 'thumbnail' ]
|
||||
}
|
||||
},
|
||||
errors_map: {
|
||||
type: 'object',
|
||||
additionalProperties: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
},
|
||||
blog: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
title: { type: 'string' },
|
||||
content: { type: 'string', 'x-nullable': true },
|
||||
thumbnail: { type: 'string'}
|
||||
},
|
||||
required: [ 'id', 'title', 'content', 'thumbnail' ]
|
||||
securitySchemes: {
|
||||
basic_auth: {
|
||||
type: :http,
|
||||
scheme: :basic
|
||||
},
|
||||
api_key: {
|
||||
type: :apiKey,
|
||||
name: 'api_key',
|
||||
in: :query
|
||||
}
|
||||
}
|
||||
},
|
||||
securityDefinitions: {
|
||||
basic_auth: {
|
||||
type: :basic
|
||||
},
|
||||
api_key: {
|
||||
type: :apiKey,
|
||||
name: 'api_key',
|
||||
in: :query
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
@ -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,57 +225,70 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"errors_object": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"errors": {
|
||||
"$ref": "#/definitions/errors_map"
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://{defaultHost}",
|
||||
"variables": {
|
||||
"defaultHost": {
|
||||
"default": "www.example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"errors_map": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"blog": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"x-nullable": true
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"components": {
|
||||
"schemas": {
|
||||
"errors_object": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"errors": {
|
||||
"$ref": "#/components/schemas/errors_map"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"content",
|
||||
"thumbnail"
|
||||
]
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"basic_auth": {
|
||||
"type": "basic"
|
||||
"errors_map": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"blog": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"content",
|
||||
"thumbnail"
|
||||
]
|
||||
}
|
||||
},
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "api_key",
|
||||
"in": "query"
|
||||
"securitySchemes": {
|
||||
"basic_auth": {
|
||||
"type": "http",
|
||||
"scheme": "basic"
|
||||
},
|
||||
"api_key": {
|
||||
"type": "apiKey",
|
||||
"name": "api_key",
|
||||
"in": "query"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user