Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Open api3 rebased #928

Draft
wants to merge 55 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
4604e1a
wip: openapi 3.0
Oct 13, 2018
f29e14c
move files to respective version folders
Oct 14, 2018
ac90d9f
begin to parse params
Oct 20, 2018
6bac652
fix failing tests
Nov 1, 2018
af9b11d
Initial support for openapi3 requestBody
Nov 10, 2018
c266c5b
OpenAPI3 parameters and request bodies are actually OpenAPI3 compliant
Nov 12, 2018
c7170da
Fix array parameter type (not custom types for now)
Nov 16, 2018
94a3fee
add tests
Nov 17, 2018
3189dfa
Initial support for openapi3 components/schemas
Nov 17, 2018
d3120f8
Fix tests
Nov 17, 2018
7f846a6
Add test
Nov 18, 2018
54de96d
Add test
Nov 25, 2018
aeb40a7
Fix edge cases with ranges, floats and strings
Nov 25, 2018
1c85b58
Add test
Nov 25, 2018
ce8c852
Add test
Nov 25, 2018
a7872ca
Add test
Nov 25, 2018
f0f2816
Add test
Nov 25, 2018
48932a5
Add test
Nov 25, 2018
ac5ad64
Better implementation of request body
Nov 30, 2018
a41d712
Fix test
Nov 30, 2018
c2e6a5a
Add test
Nov 30, 2018
47ec64e
Add test
Nov 30, 2018
5d3b522
Add test
Nov 30, 2018
d305600
fix array test
Dec 2, 2018
dcdcc38
Fix test
Dec 6, 2018
1518be3
Add test
Dec 6, 2018
8998cbf
Add test
Dec 6, 2018
e1d09c1
Add test
Dec 6, 2018
3eb21a2
Add test
Dec 6, 2018
12e7a4f
Add test
Dec 6, 2018
d65d13e
Add test
Dec 6, 2018
bbf21b9
Add test
Dec 6, 2018
5ff4d39
Add test
Dec 6, 2018
4c470fb
Add test
Dec 6, 2018
f50a24a
Fix tests
Dec 6, 2018
7a3fb37
Add test
Dec 7, 2018
a89c16f
Add test
Dec 7, 2018
c0d9ee9
Add test
Dec 7, 2018
7199caf
Add test
Dec 7, 2018
1ebeb33
Fix file response body
Dec 11, 2018
b3eaa88
Add examples spec
Dec 17, 2018
b4c95fe
Fix host test
Dec 27, 2018
230efaf
Add specs
Dec 27, 2018
5d6bb3a
Fix guarded endpoint spec, after a rebase
Dec 28, 2018
9713a2b
Fix spec
Dec 28, 2018
1f9c449
Add spec
Dec 30, 2018
9b6cb2a
Add spec
Jan 20, 2019
2cbb17b
Fix: Prevent class name collisions in specs with ApiClassDefinitionCl…
numbata Jul 13, 2024
fd14ca9
Fix ParamsParser call from OpenAPI3 module
numbata Jul 13, 2024
f55b906
Skip anonymous API class definition deletion in specs
numbata Jul 13, 2024
510457f
Cleanup a bit
numbata Jul 14, 2024
752525a
Set the right $ref object for the request body
numbata Jul 14, 2024
dcecc68
Specs fix
numbata Jul 14, 2024
00ed99e
Add schema validation against OpenAPI3 specification
numbata Jul 14, 2024
5288b69
Getting rid of the debug noise a little bit
numbata Jul 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ group :development, :test do
gem 'rdoc'
gem 'rspec', '~> 3.9'
gem 'rubocop', '~> 1.50', require: false
gem "openapi3_parser", "~> 0.10.0"

unless ENV['MODEL_PARSER'] == 'grape-swagger-entity'
gem 'grape-swagger-entity', git: 'https://github.com/ruby-grape/grape-swagger-entity'
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ get '/thing', failure: [
# ...
end
```
If no status code is defined [defaults](/lib/grape-swagger/endpoint.rb#L210) would be taken.
If no status code is defined [defaults](/lib/grape-swagger/swagger_2/endpoint.rb#L210) would be taken.

The result is then something like following:

Expand Down
33 changes: 24 additions & 9 deletions lib/grape-swagger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

require 'grape-swagger/instance'

require 'grape-swagger/version'
require 'grape-swagger/endpoint'
require 'grape-swagger/errors'

require 'grape-swagger/doc_methods'
require 'grape-swagger/version'
require 'grape-swagger/model_parsers'
require 'grape-swagger/swagger_2/endpoint'
require 'grape-swagger/openapi_3/endpoint'
require 'grape-swagger/openapi_3/doc_methods'
require 'grape-swagger/swagger_2/doc_methods'

module GrapeSwagger
class << self
Expand Down Expand Up @@ -122,11 +123,10 @@ module SwaggerDocumentationAdder
include SwaggerRouting

def add_swagger_documentation(options = {})
documentation_class = create_documentation_class

version_for(options)
options = { target_class: self }.merge(options)
version_for(options)
@target_class = options[:target_class]
documentation_class = create_documentation_class(options[:openapi_version])
auth_wrapper = options[:endpoint_auth_wrapper] || Class.new

use auth_wrapper if auth_wrapper.method_defined?(:before) && !middleware.flatten.include?(auth_wrapper)
Expand All @@ -144,6 +144,10 @@ def add_swagger_documentation(options = {})
@target_class.combined_routes = combined_routes
@target_class.combined_namespaces = combined_namespaces

endpoint_type = options[:openapi_version] == '3.0' ? Grape::OpenAPI3Endpoint : Grape::Swagger2Endpoint
set_endpoint_type(@target_class, endpoint_type)
set_endpoint_type(documentation_class, endpoint_type)

documentation_class
end

Expand All @@ -153,6 +157,13 @@ def version_for(options)
options[:version] = version if version
end

def set_endpoint_type(app, klass)
app.endpoints.each do |endpoint|
endpoint.class.include(klass)
set_endpoint_type(endpoint.options[:app], klass) if endpoint.options[:app]
end
end

def combine_namespaces(app)
combined_namespaces = {}
endpoints = app.endpoints.clone
Expand All @@ -174,9 +185,13 @@ def combine_namespaces(app)
combined_namespaces
end

def create_documentation_class
def create_documentation_class(openapi_version)
Class.new(GrapeInstance) do
extend GrapeSwagger::DocMethods
if openapi_version == '3.0'
extend GrapeOpenAPI::DocMethods
else
extend GrapeSwagger::DocMethods
end
end
end
end
Expand Down
12 changes: 10 additions & 2 deletions lib/grape-swagger/doc_methods/extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,17 @@ def find_definition(status, path)
response = path[method][:responses][status]
return if response.nil?

return response[:schema]['$ref'].split('/').last if response[:schema].key?('$ref')
# Swagger 2
if response[:schema]
return response[:schema]['$ref'].split('/').last if response[:schema].key?('$ref')
return response[:schema]['items']['$ref'].split('/').last if response[:schema].key?('items')
end

response[:schema]['items']['$ref'].split('/').last if response[:schema].key?('items')
# OpenAPI 3
response[:content].each do |_,v|
return v[:schema]['$ref'].split('/').last if v[:schema].key?('$ref')
return v[:schema]['items']['$ref'].split('/').last if v[:schema].key?('items')
end
end

def add_extension_to(part, extensions)
Expand Down
2 changes: 2 additions & 0 deletions lib/grape-swagger/doc_methods/parse_params.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'grape-swagger/endpoint/info_object_builder'

module GrapeSwagger
module DocMethods
class ParseParams
Expand Down
52 changes: 52 additions & 0 deletions lib/grape-swagger/endpoint/info_object_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

module GrapeSwagger
module Endpoint
class InfoObjectBuilder
attr_reader :infos

def self.build(infos)
new(infos).build
end

def initialize(infos)
@infos = infos
end

def build
result = {
title: infos[:title] || 'API title',
description: infos[:description],
termsOfService: infos[:terms_of_service_url],
contact: contact_object,
license: license_object,
version: infos[:version]
}

GrapeSwagger::DocMethods::Extensions.add_extensions_to_info(infos, result)

result.delete_if { |_, value| value.blank? }
end

private

# sub-objects of info object
# license
def license_object
{
name: infos[:license],
url: infos[:license_url]
}.delete_if { |_, value| value.blank? }
end

# contact
def contact_object
{
name: infos[:contact_name],
email: infos[:contact_email],
url: infos[:contact_url]
}.delete_if { |_, value| value.blank? }
end
end
end
end
137 changes: 137 additions & 0 deletions lib/grape-swagger/openapi_3/doc_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# frozen_string_literal: true

require 'grape-swagger/doc_methods/status_codes'
require 'grape-swagger/doc_methods/produces_consumes'
require 'grape-swagger/doc_methods/data_type'
require 'grape-swagger/doc_methods/extensions'
require 'grape-swagger/doc_methods/operation_id'
require 'grape-swagger/doc_methods/optional_object'
require 'grape-swagger/doc_methods/path_string'
require 'grape-swagger/doc_methods/tag_name_description'
require 'grape-swagger/openapi_3/doc_methods/parse_params'
require 'grape-swagger/openapi_3/doc_methods/move_params'
require 'grape-swagger/doc_methods/headers'
require 'grape-swagger/doc_methods/build_model_definition'
require 'grape-swagger/doc_methods/version'

module GrapeOpenAPI
module DocMethods
def hide_documentation_path
@@hide_documentation_path
end

def mount_path
@@mount_path
end

def setup(options)
options = defaults.merge(options)

# options could be set on #add_swagger_documentation call,
# for available options see #defaults
target_class = options[:target_class]
guard = options[:swagger_endpoint_guard]
formatter = options[:format]
api_doc = options[:api_documentation].dup
specific_api_doc = options[:specific_api_documentation].dup

class_variables_from(options)

if formatter
%i[format default_format default_error_formatter].each do |method|
send(method, formatter)
end
end

desc api_doc.delete(:desc), api_doc

instance_eval(guard) unless guard.nil?

output_path_definitions = proc do |combi_routes, endpoint|
output = endpoint.swagger_object(
target_class,
endpoint.request,
options
)

paths, definitions = endpoint.path_and_definition_objects(combi_routes, target_class, options)
tags = tags_from(paths, options)

output[:tags] = tags unless tags.empty? || paths.blank?
output[:paths] = paths unless paths.blank?
unless definitions.blank?
output[:components] ||= {}
output[:components][:schemas] = definitions
end

output
end

get mount_path do
header['Access-Control-Allow-Origin'] = '*'
header['Access-Control-Request-Method'] = '*'

output_path_definitions.call(target_class.combined_namespace_routes, self)
end

desc specific_api_doc.delete(:desc), { params:
specific_api_doc.delete(:params) || {} }.merge(specific_api_doc)

params do
requires :name, type: String, desc: 'Resource name of mounted API'
optional :locale, type: Symbol, desc: 'Locale of API documentation'
end

get "#{mount_path}/:name" do
I18n.locale = params[:locale] || I18n.default_locale

combined_routes = target_class.combined_namespace_routes[params[:name]]
error!({ error: 'named resource not exist' }, 400) if combined_routes.nil?

output_path_definitions.call({ params[:name] => combined_routes }, self)
end
end

def defaults
{
info: {},
models: [],
doc_version: '0.0.1',
target_class: nil,
mount_path: '/swagger_doc',
host: nil,
base_path: nil,
add_base_path: false,
add_version: true,
hide_documentation_path: true,
format: :json,
authorizations: nil,
security_definitions: nil,
security: nil,
api_documentation: { desc: 'Swagger compatible API description' },
specific_api_documentation: { desc: 'Swagger compatible API description for specific API' },
endpoint_auth_wrapper: nil,
swagger_endpoint_guard: nil,
token_owner: nil
}
end

def class_variables_from(options)
@@mount_path = options[:mount_path]
@@class_name = options[:class_name] || options[:mount_path].delete('/')
@@hide_documentation_path = options[:hide_documentation_path]
end

def tags_from(paths, options)
tags = GrapeSwagger::DocMethods::TagNameDescription.build(paths)

if options[:tags]
names = options[:tags].map { |t| t[:name] }
tags.reject! { |t| names.include?(t[:name]) }
tags += options[:tags]
end

tags
end
end
end
Loading
Loading