grape-swagger 0.10.2 → 0.10.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +37 -16
- data/.travis.yml +1 -0
- data/CHANGELOG.md +10 -0
- data/README.md +195 -1
- data/example/config.ru +1 -1
- data/grape-swagger.gemspec +2 -2
- data/lib/grape-swagger.rb +8 -2
- data/lib/grape-swagger/doc_methods.rb +124 -40
- data/lib/grape-swagger/markdown.rb +1 -1
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/api_description_spec.rb +6 -4
- data/spec/array_params_spec.rb +5 -5
- data/spec/boolean_params_spec.rb +1 -1
- data/spec/default_api_spec.rb +1 -2
- data/spec/float_api_spec.rb +1 -1
- data/spec/group_params_spec.rb +2 -2
- data/spec/hash_params_spec.rb +1 -1
- data/spec/i18n_spec.rb +364 -0
- data/spec/mutually_exclusive_spec.rb +2 -2
- data/spec/non_default_api_spec.rb +0 -1
- data/spec/param_type_spec.rb +6 -4
- data/spec/param_values_spec.rb +6 -6
- data/spec/spec_helper.rb +3 -0
- data/spec/support/i18n_helper.rb +8 -0
- metadata +12 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c3b14815684b5e4e77c01b12a1c64029b4cc367
|
4
|
+
data.tar.gz: ecd30bdba3542f6a776c7f94683aab2a2eb32989
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b2baa995bd32ba699ea6ffc21fb3816b5a6742a2b3be229df6a47e3cdf85622a52468899c1e5cee3b7f77973fe5dcedfa1330b390a981d09ebca7a47b6bdfbd
|
7
|
+
data.tar.gz: 96a44e9923a0921f2f368f6f128681fa40796c3987fc46a7de54aec2599d00f0de33b42db4f19b5062857155fbf7395f50c25c95f112f43c86db0a525b9e0920
|
data/.rubocop_todo.yml
CHANGED
@@ -1,55 +1,76 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
#
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2015-08-19 12:17:53 -0400 using RuboCop version 0.33.0.
|
3
4
|
# The point is for the user to remove these configuration records
|
4
5
|
# one by one as the offenses are removed from the code base.
|
5
6
|
# Note that changes in the inspected code, or installation of new
|
6
7
|
# versions of RuboCop, may require this file to be generated again.
|
7
8
|
|
8
|
-
# Offense count:
|
9
|
+
# Offense count: 10
|
9
10
|
Metrics/AbcSize:
|
10
|
-
Max:
|
11
|
+
Max: 214
|
11
12
|
|
12
13
|
# Offense count: 1
|
13
14
|
# Configuration parameters: CountComments.
|
14
15
|
Metrics/ClassLength:
|
15
|
-
Max:
|
16
|
+
Max: 147
|
16
17
|
|
17
18
|
# Offense count: 6
|
18
19
|
Metrics/CyclomaticComplexity:
|
19
|
-
Max:
|
20
|
+
Max: 39
|
20
21
|
|
21
|
-
# Offense count:
|
22
|
+
# Offense count: 304
|
22
23
|
# Configuration parameters: AllowURI, URISchemes.
|
23
24
|
Metrics/LineLength:
|
24
|
-
Max:
|
25
|
+
Max: 242
|
25
26
|
|
26
27
|
# Offense count: 21
|
27
28
|
# Configuration parameters: CountComments.
|
28
29
|
Metrics/MethodLength:
|
29
|
-
Max:
|
30
|
+
Max: 170
|
30
31
|
|
31
|
-
# Offense count:
|
32
|
+
# Offense count: 1
|
33
|
+
# Configuration parameters: CountComments.
|
34
|
+
Metrics/ModuleLength:
|
35
|
+
Max: 470
|
36
|
+
|
37
|
+
# Offense count: 4
|
32
38
|
Metrics/PerceivedComplexity:
|
33
|
-
Max:
|
39
|
+
Max: 41
|
34
40
|
|
35
41
|
# Offense count: 8
|
36
42
|
Style/ClassVars:
|
37
|
-
|
43
|
+
Exclude:
|
44
|
+
- 'example/api.rb'
|
45
|
+
- 'lib/grape-swagger/doc_methods.rb'
|
38
46
|
|
39
|
-
# Offense count:
|
47
|
+
# Offense count: 90
|
40
48
|
Style/Documentation:
|
41
49
|
Enabled: false
|
42
50
|
|
43
51
|
# Offense count: 2
|
44
52
|
Style/DoubleNegation:
|
45
|
-
|
53
|
+
Exclude:
|
54
|
+
- 'lib/grape-swagger/doc_methods.rb'
|
46
55
|
|
47
56
|
# Offense count: 3
|
48
57
|
# Configuration parameters: Exclude.
|
49
58
|
Style/FileName:
|
50
|
-
|
59
|
+
Exclude:
|
60
|
+
- 'lib/grape-swagger.rb'
|
61
|
+
- 'spec/grape-swagger_helper_spec.rb'
|
62
|
+
- 'spec/grape-swagger_spec.rb'
|
51
63
|
|
52
64
|
# Offense count: 1
|
53
65
|
# Configuration parameters: NamePrefix, NamePrefixBlacklist.
|
54
66
|
Style/PredicateName:
|
55
|
-
|
67
|
+
Exclude:
|
68
|
+
- 'lib/grape-swagger/doc_methods.rb'
|
69
|
+
|
70
|
+
# Offense count: 4
|
71
|
+
# Cop supports --auto-correct.
|
72
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
73
|
+
Style/RegexpLiteral:
|
74
|
+
Exclude:
|
75
|
+
- 'lib/grape-swagger.rb'
|
76
|
+
- 'lib/grape-swagger/doc_methods.rb'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
### 0.10.4 (December 7, 2015)
|
2
|
+
|
3
|
+
* [#315](https://github.com/ruby-grape/grape-swagger/pull/315): Require `grape-entity` < 0.5.0 - [@dblock](https://github.com/dblock).
|
4
|
+
|
5
|
+
### 0.10.3 (December 7, 2015)
|
6
|
+
|
7
|
+
* [#292](https://github.com/ruby-grape/grape-swagger/pull/292): Support i18n - [@calfzhou](https://github.com/calfzhou).
|
8
|
+
* [#297](https://github.com/ruby-grape/grape-swagger/pull/297): Correct use of documentation param_type - [@fab-girard](https://github.com/fab-girard).
|
9
|
+
* [#305](https://github.com/ruby-grape/grape-swagger/pull/305): Speedup by parsing models smarter, not harder - [@jhollinger](https://github.com/jhollinger).
|
10
|
+
|
1
11
|
### 0.10.2 (August 19, 2015)
|
2
12
|
|
3
13
|
#### Features
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/grape-swagger.svg)](http://badge.fury.io/rb/grape-swagger)
|
4
4
|
[![Build Status](https://travis-ci.org/ruby-grape/grape-swagger.svg?branch=master)](https://travis-ci.org/ruby-grape/grape-swagger)
|
5
|
+
[![Dependency Status](https://gemnasium.com/ruby-grape/grape-swagger.svg)](https://gemnasium.com/ruby-grape/grape-swagger)
|
5
6
|
[![Code Climate](https://codeclimate.com/github/ruby-grape/grape-swagger.svg)](https://codeclimate.com/github/ruby-grape/grape-swagger)
|
6
7
|
|
7
8
|
## What is grape-swagger?
|
@@ -92,6 +93,10 @@ API class name.
|
|
92
93
|
|
93
94
|
Allow markdown in `detail`/`notes`, default is `nil`. (disabled) See below for details.
|
94
95
|
|
96
|
+
#### i18n_scope
|
97
|
+
|
98
|
+
Translations scope (or array of scopes) default is `:api`. [See below for details](#i18n).
|
99
|
+
|
95
100
|
#### hide_format
|
96
101
|
|
97
102
|
Don't add `.(format)` to the end of URLs, default is `false`.
|
@@ -305,7 +310,7 @@ Grape uses the option `default` to set a default value for optional parameters.
|
|
305
310
|
|
306
311
|
## Grape Entities
|
307
312
|
|
308
|
-
Add the [grape-entity](https://github.com/
|
313
|
+
Add the [grape-entity](https://github.com/ruby-grape/grape-entity) gem to our Gemfile.
|
309
314
|
|
310
315
|
The following example exposes statuses. And exposes statuses documentation adding :type and :desc.
|
311
316
|
|
@@ -511,6 +516,195 @@ get '/', http_codes: [
|
|
511
516
|
end
|
512
517
|
```
|
513
518
|
|
519
|
+
## I18n
|
520
|
+
|
521
|
+
Grape-swagger supports I18n for most messages of the JSON documentation, including:
|
522
|
+
|
523
|
+
* API [info](#info)
|
524
|
+
* Namespaces/resources description
|
525
|
+
* Endpoints description and detail/notes
|
526
|
+
* Params (including headers) description
|
527
|
+
* Models/entities description
|
528
|
+
|
529
|
+
By default, grape-swagger will lookup translations inside `:api` scope. This can be configured by
|
530
|
+
set [`i18n_scope`](#i18n_scope) to a custom scope (or an array of scopes) when calling
|
531
|
+
`add_swagger_documentation`.
|
532
|
+
|
533
|
+
### Translation and Default Message
|
534
|
+
|
535
|
+
To localize your API document, you can add a locale file containing translated messages.
|
536
|
+
Grape-swagger will try to look up translation for each message. If a translation cannot be found,
|
537
|
+
it will use the message specified in the API code, then default to blank.
|
538
|
+
|
539
|
+
Take the following sample API for example:
|
540
|
+
|
541
|
+
```ruby
|
542
|
+
desc 'Gets all kittens' do
|
543
|
+
detail 'This will expose all the kittens.'
|
544
|
+
end
|
545
|
+
params do
|
546
|
+
optional :sort
|
547
|
+
end
|
548
|
+
get :kittens do
|
549
|
+
end
|
550
|
+
```
|
551
|
+
|
552
|
+
To generate I18n documentation, you can add a locale file with translated messages:
|
553
|
+
|
554
|
+
```yaml
|
555
|
+
api:
|
556
|
+
kittens:
|
557
|
+
get:
|
558
|
+
detail: This will return a full list of kittens, and you can change the way of sorting them.
|
559
|
+
params:
|
560
|
+
sort: Specifies the order of results
|
561
|
+
```
|
562
|
+
|
563
|
+
The endpoint description in generated API document will be "Gets all kittens" - specified in source
|
564
|
+
code - because there is no translation defined. And endpoint details will be overwritten by locale
|
565
|
+
message - "This will return a full list of kittens, and you can change the way of sorting them.".
|
566
|
+
Parameter `:sort` will have a description from locale file too.
|
567
|
+
|
568
|
+
### Default Lookup Keys
|
569
|
+
|
570
|
+
The following lookup keys are all within the scope given by `i18n_scope`.
|
571
|
+
|
572
|
+
#### API Info
|
573
|
+
|
574
|
+
The default lookup key of a field in API info is `info.<field>`, i.e.:
|
575
|
+
|
576
|
+
* `info.title` for `:title` field.
|
577
|
+
* `info.desc` or `info.description` for `:description` field.
|
578
|
+
* `info.contact` for `:contact` field.
|
579
|
+
* `info.license` for `:license` field.
|
580
|
+
* `info.license_url` for `:license_url` field.
|
581
|
+
* `info.terms_of_service_url` for `:terms_of_service_url` field.
|
582
|
+
|
583
|
+
#### Namespaces/Resources Description
|
584
|
+
|
585
|
+
Grape-swagger will give each root namespace a default description, such as "*Operations about
|
586
|
+
users*", where `users` is a namespace (pluralized). But you can change it by provide your own
|
587
|
+
message under key `<namespace>.desc` or `<namespace>.description` in your locale file. And the
|
588
|
+
namespace itself is available as a variable for interpolation.
|
589
|
+
|
590
|
+
### Endpoints Description and Detail/Notes
|
591
|
+
|
592
|
+
An endpoint's default lookup key is in format of `<namespace>.<path>.<http_method>`. And if there
|
593
|
+
are nested namespaces or multi-level path, all parts will be join by `.`. For example for this
|
594
|
+
endpoint:
|
595
|
+
|
596
|
+
```ruby
|
597
|
+
namespace :users do
|
598
|
+
route_params :id do
|
599
|
+
get :'password/strength' do
|
600
|
+
end
|
601
|
+
end
|
602
|
+
end
|
603
|
+
```
|
604
|
+
|
605
|
+
Its corresponding lookup key will be `users.:id.password.strength.get`, let's say that this is
|
606
|
+
the key of this endpoint.
|
607
|
+
|
608
|
+
So an endpoint's description message can be given under `<endpoint_key>.desc` or
|
609
|
+
`<endpoint_key>.description`. And use `<endpoint_key>.detail` or `<endpoint_key>.notes` for the
|
610
|
+
message of its further details.
|
611
|
+
|
612
|
+
#### Params Description
|
613
|
+
|
614
|
+
The first default key of endpoint parameter's description translation is
|
615
|
+
`<endpoint_key>.params.<param_name>`. But considering that some endpoints could usually share a
|
616
|
+
same parameter, it will be a little annoyed to duplicate its description message everywhere. So if
|
617
|
+
no translation found in the first default key, grape-swagger will try to find all its parent keys.
|
618
|
+
Take above endpoint for example, it may have a parameter named `:id`, then the lookup keys are:
|
619
|
+
|
620
|
+
1. `users.:id.password.strength.get.params.id`
|
621
|
+
1. `users.:id.password.strength.params.id`
|
622
|
+
1. `users.:id.password.params.id`
|
623
|
+
1. `users.:id.params.id`
|
624
|
+
1. `users.params.id`
|
625
|
+
1. `params.id`
|
626
|
+
|
627
|
+
#### Models/Entities Description
|
628
|
+
|
629
|
+
A model class' lookup key is by default its class name, without module part, and underscored. Each
|
630
|
+
property's key is then `entities.<class_key>.<property_name>`. When not found, grape-swagger will
|
631
|
+
try to check the its ancestors, up to a class whose name is `Entity`.
|
632
|
+
|
633
|
+
Say if there is model class `User` inherits `Grape::Entity`, and another model `AdminUser` inherits
|
634
|
+
`User`, to translate a property named `:email` of `AdminUser`, the lookup keys are:
|
635
|
+
|
636
|
+
1. `entities.admin_user.email`
|
637
|
+
1. `entities.user.email`
|
638
|
+
1. `entities.default.email`
|
639
|
+
|
640
|
+
#### Example Locale File
|
641
|
+
|
642
|
+
```yaml
|
643
|
+
en:
|
644
|
+
api:
|
645
|
+
info:
|
646
|
+
title: My Awesome API
|
647
|
+
desc: Some detail information about this API.
|
648
|
+
entities:
|
649
|
+
default:
|
650
|
+
id: Resource identifier
|
651
|
+
user:
|
652
|
+
name: User's real name
|
653
|
+
email: User's login email address
|
654
|
+
sign_up_at: When the user signed up
|
655
|
+
admin_user:
|
656
|
+
level: Which level the admin is
|
657
|
+
password_strength:
|
658
|
+
level: A 0~4 integer indicates `very_weak` to `strong`
|
659
|
+
crack_time: An estimated time for force cracking the password, in seconds
|
660
|
+
params:
|
661
|
+
locale: Used to change locale of endpoint's responding message
|
662
|
+
sort: To specify the order of result list, default is %{default_sort}
|
663
|
+
users:
|
664
|
+
desc: Operations about not-disabled users
|
665
|
+
get:
|
666
|
+
desc: Gets a list of users
|
667
|
+
detail: You can control how to sort the results.
|
668
|
+
':id':
|
669
|
+
params:
|
670
|
+
id: User id
|
671
|
+
get:
|
672
|
+
desc: Finds user by id
|
673
|
+
email:
|
674
|
+
put:
|
675
|
+
desc: Changes a user's email
|
676
|
+
params:
|
677
|
+
email: A new email
|
678
|
+
password:
|
679
|
+
strength:
|
680
|
+
get:
|
681
|
+
desc: Gets the strength estimation of a user's password
|
682
|
+
detail: The estimation is done by a well-known algorithm when he changed his password
|
683
|
+
swagger_doc:
|
684
|
+
desc: Endpoints for API documents
|
685
|
+
get:
|
686
|
+
desc: Gets root API document
|
687
|
+
':name':
|
688
|
+
get:
|
689
|
+
desc: Gets specific resource API document
|
690
|
+
params:
|
691
|
+
name: Resource name
|
692
|
+
```
|
693
|
+
|
694
|
+
### Customization
|
695
|
+
|
696
|
+
The translation can be customized by using different kind/format of message in source code.
|
697
|
+
|
698
|
+
* A string or `nil`: It will become the default message when a translation is not defined.
|
699
|
+
* A symbol: Looks up translation using the symbol as a key, but will fallback to default key(s).
|
700
|
+
* A hash with the following keys:
|
701
|
+
* key: A symbol, defines custom lookup key.
|
702
|
+
* default: A string, defines the default message when translation can not be found.
|
703
|
+
* translate: A boolean (default is `true`), set to `false` to skip translation for this message.
|
704
|
+
* scope: A symbol, or a string, or an array of them. Used to replace the `i18n_scope` config
|
705
|
+
value for a custom lookup scope.
|
706
|
+
* Any other key/value will be sent to the translation function for interpolation.
|
707
|
+
|
514
708
|
## Contributing to grape-swagger
|
515
709
|
|
516
710
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
data/example/config.ru
CHANGED
data/grape-swagger.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.license = 'MIT'
|
13
13
|
|
14
14
|
s.add_runtime_dependency 'grape', '>= 0.8.0'
|
15
|
-
s.add_runtime_dependency 'grape-entity'
|
15
|
+
s.add_runtime_dependency 'grape-entity', '< 0.5.0'
|
16
16
|
|
17
17
|
s.add_development_dependency 'rake'
|
18
18
|
s.add_development_dependency 'shoulda'
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_development_dependency 'bundler'
|
22
22
|
s.add_development_dependency 'rack-test'
|
23
23
|
s.add_development_dependency 'rack-cors'
|
24
|
-
s.add_development_dependency 'rubocop', '0.
|
24
|
+
s.add_development_dependency 'rubocop', '0.33.0'
|
25
25
|
s.add_development_dependency 'kramdown', '~> 1.4.1'
|
26
26
|
s.add_development_dependency 'redcarpet', '~> 3.1.2' unless RUBY_PLATFORM.eql? 'java'
|
27
27
|
s.add_development_dependency 'rouge', '~> 1.6.1'
|
data/lib/grape-swagger.rb
CHANGED
@@ -10,6 +10,7 @@ module Grape
|
|
10
10
|
class API
|
11
11
|
class << self
|
12
12
|
attr_accessor :combined_routes, :combined_namespaces, :combined_namespace_routes, :combined_namespace_identifiers
|
13
|
+
attr_accessor :endpoint_mapping
|
13
14
|
|
14
15
|
def add_swagger_documentation(options = {})
|
15
16
|
documentation_class = create_documentation_class
|
@@ -35,6 +36,7 @@ module Grape
|
|
35
36
|
@target_class.combined_routes[resource] << route
|
36
37
|
end
|
37
38
|
|
39
|
+
@target_class.endpoint_mapping = {}
|
38
40
|
@target_class.combined_namespaces = {}
|
39
41
|
combine_namespaces(@target_class)
|
40
42
|
|
@@ -60,6 +62,10 @@ module Grape
|
|
60
62
|
# and strip leading slash
|
61
63
|
@target_class.combined_namespaces[endpoint.namespace.sub(/^\//, '')] = ns if ns
|
62
64
|
|
65
|
+
endpoint.routes.each do |route|
|
66
|
+
@target_class.endpoint_mapping[route.to_s.sub('(.:format)', '')] = endpoint
|
67
|
+
end
|
68
|
+
|
63
69
|
combine_namespaces(endpoint.options[:app]) if endpoint.options[:app]
|
64
70
|
end
|
65
71
|
end
|
@@ -79,9 +85,9 @@ module Grape
|
|
79
85
|
if namespace.options.key?(:swagger) && namespace.options[:swagger][:nested] == false
|
80
86
|
# Namespace shall appear as standalone resource, use specified name or use normalized path as name
|
81
87
|
if namespace.options[:swagger].key?(:name)
|
82
|
-
identifier = namespace.options[:swagger][:name].
|
88
|
+
identifier = namespace.options[:swagger][:name].tr(' ', '-')
|
83
89
|
else
|
84
|
-
identifier = name.
|
90
|
+
identifier = name.tr('_', '-').gsub(/\//, '_')
|
85
91
|
end
|
86
92
|
@target_class.combined_namespace_identifiers[identifier] = name
|
87
93
|
@target_class.combined_namespace_routes[identifier] = namespace_routes
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module GrapeSwagger
|
2
4
|
module DocMethods
|
3
5
|
PRIMITIVE_MAPPINGS = {
|
@@ -14,11 +16,43 @@ module GrapeSwagger
|
|
14
16
|
@@class_name
|
15
17
|
end
|
16
18
|
|
19
|
+
def translate(message, scope, default, params = {})
|
20
|
+
if message.is_a?(String)
|
21
|
+
text = message
|
22
|
+
elsif message.is_a?(Symbol)
|
23
|
+
key = message
|
24
|
+
elsif message.is_a?(Hash)
|
25
|
+
message = message.dup
|
26
|
+
key = message.delete(:key)
|
27
|
+
text = message.delete(:default)
|
28
|
+
skip_translate = !message.delete(:translate) if message.key?(:translate)
|
29
|
+
scope = message.delete(:scope) if message.key?(:scope)
|
30
|
+
params = params.merge(message) unless message.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
return text if skip_translate
|
34
|
+
|
35
|
+
default = Array(default).dup << (text || '')
|
36
|
+
I18n.t(key, params.merge(scope: scope, default: default))
|
37
|
+
end
|
38
|
+
|
39
|
+
def expand_scope(scope)
|
40
|
+
scopes = []
|
41
|
+
scope = scope.to_s
|
42
|
+
until scope.blank?
|
43
|
+
scopes << scope.to_sym
|
44
|
+
scope = scope.rpartition('.')[0]
|
45
|
+
end
|
46
|
+
scopes << :''
|
47
|
+
end
|
48
|
+
|
17
49
|
def as_markdown(description)
|
18
50
|
description && @@markdown ? @@markdown.as_markdown(strip_heredoc(description)) : description
|
19
51
|
end
|
20
52
|
|
21
|
-
def parse_params(params, path, method)
|
53
|
+
def parse_params(params, path, method, options = {})
|
54
|
+
scope = options[:scope]
|
55
|
+
i18n_keys = expand_scope(options[:key])
|
22
56
|
params ||= []
|
23
57
|
|
24
58
|
parsed_array_params = parse_array_params(params)
|
@@ -71,27 +105,29 @@ module GrapeSwagger
|
|
71
105
|
values = value.is_a?(Hash) ? value[:values] : nil
|
72
106
|
enum_or_range_values = parse_enum_or_range_values(values)
|
73
107
|
|
74
|
-
if value.is_a?(Hash) && value.key?(:
|
75
|
-
param_type
|
108
|
+
if value.is_a?(Hash) && value.key?(:param_type)
|
109
|
+
param_type = value[:param_type]
|
76
110
|
if is_array
|
77
111
|
items = { '$ref' => data_type }
|
78
112
|
data_type = 'array'
|
79
113
|
end
|
80
114
|
else
|
81
|
-
param_type
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
115
|
+
param_type = case
|
116
|
+
when path.include?(":#{param}")
|
117
|
+
'path'
|
118
|
+
when %w(POST PUT PATCH).include?(method)
|
119
|
+
if is_primitive?(data_type)
|
120
|
+
'form'
|
121
|
+
else
|
122
|
+
'body'
|
123
|
+
end
|
124
|
+
else
|
125
|
+
'query'
|
92
126
|
end
|
93
127
|
end
|
94
128
|
name = (value.is_a?(Hash) && value[:full_name]) || param
|
129
|
+
description = translate(description, scope,
|
130
|
+
i18n_keys.map { |key| :"#{key}.params.#{name}" })
|
95
131
|
|
96
132
|
parsed_params = {
|
97
133
|
paramType: param_type,
|
@@ -99,14 +135,14 @@ module GrapeSwagger
|
|
99
135
|
description: as_markdown(description),
|
100
136
|
type: data_type,
|
101
137
|
required: required,
|
102
|
-
allowMultiple: is_array
|
138
|
+
allowMultiple: is_array && data_type != 'array' && %w(query header path).include?(param_type)
|
103
139
|
}
|
104
140
|
|
105
141
|
if PRIMITIVE_MAPPINGS.key?(data_type)
|
106
142
|
parsed_params[:type], parsed_params[:format] = PRIMITIVE_MAPPINGS[data_type]
|
107
143
|
end
|
108
144
|
|
109
|
-
parsed_params[:items]
|
145
|
+
parsed_params[:items] = items if items.present?
|
110
146
|
|
111
147
|
parsed_params[:defaultValue] = example if example
|
112
148
|
if default_value && example.blank?
|
@@ -130,18 +166,22 @@ module GrapeSwagger
|
|
130
166
|
content_types.uniq
|
131
167
|
end
|
132
168
|
|
133
|
-
def parse_info(info)
|
169
|
+
def parse_info(info, options = {})
|
170
|
+
scope = options[:scope]
|
171
|
+
|
134
172
|
{
|
135
|
-
contact: info[:contact],
|
136
|
-
description: as_markdown(info[:description]),
|
137
|
-
license: info[:license],
|
138
|
-
licenseUrl: info[:license_url],
|
139
|
-
termsOfServiceUrl: info[:terms_of_service_url],
|
140
|
-
title: info[:title]
|
173
|
+
contact: translate(info[:contact], scope, :'info.contact'),
|
174
|
+
description: as_markdown(translate(info[:description], scope, [:'info.desc', :'info.description'])),
|
175
|
+
license: translate(info[:license], scope, :'info.license'),
|
176
|
+
licenseUrl: translate(info[:license_url], scope, :'info.license_url'),
|
177
|
+
termsOfServiceUrl: translate(info[:terms_of_service_url], scope, :'info.terms_of_service_url'),
|
178
|
+
title: translate(info[:title], scope, :'info.title')
|
141
179
|
}.delete_if { |_, value| value.blank? }
|
142
180
|
end
|
143
181
|
|
144
|
-
def parse_header_params(params)
|
182
|
+
def parse_header_params(params, options = {})
|
183
|
+
scope = options[:scope]
|
184
|
+
i18n_keys = expand_scope(options[:key])
|
145
185
|
params ||= []
|
146
186
|
|
147
187
|
params.map do |param, value|
|
@@ -151,6 +191,9 @@ module GrapeSwagger
|
|
151
191
|
default_value = value.is_a?(Hash) ? value[:default] : nil
|
152
192
|
param_type = 'header'
|
153
193
|
|
194
|
+
description = translate(description, scope,
|
195
|
+
i18n_keys.map { |key| :"#{key}.params.#{param}" })
|
196
|
+
|
154
197
|
parsed_params = {
|
155
198
|
paramType: param_type,
|
156
199
|
name: param,
|
@@ -191,13 +234,22 @@ module GrapeSwagger
|
|
191
234
|
end
|
192
235
|
end
|
193
236
|
|
194
|
-
def parse_entity_models(models)
|
237
|
+
def parse_entity_models(models, options = {})
|
238
|
+
scope = options[:scope]
|
195
239
|
result = {}
|
196
240
|
models.each do |model|
|
197
241
|
name = (model.instance_variable_get(:@root) || parse_entity_name(model))
|
198
242
|
properties = {}
|
199
243
|
required = []
|
200
244
|
|
245
|
+
i18n_keys = []
|
246
|
+
klass = model
|
247
|
+
until %w(entity object).include? klass.name.demodulize.underscore
|
248
|
+
i18n_keys << klass.name.demodulize.underscore.to_sym
|
249
|
+
klass = klass.superclass
|
250
|
+
end
|
251
|
+
i18n_keys << :default
|
252
|
+
|
201
253
|
model.documentation.each do |property_name, property_info|
|
202
254
|
p = property_info.dup
|
203
255
|
|
@@ -219,7 +271,9 @@ module GrapeSwagger
|
|
219
271
|
|
220
272
|
# rename Grape Entity's "desc" to "description"
|
221
273
|
property_description = p.delete(:desc)
|
222
|
-
|
274
|
+
property_description = translate(property_description, scope,
|
275
|
+
i18n_keys.map { |key| :"entities.#{key}.#{property_name}" })
|
276
|
+
p[:description] = property_description unless property_description.blank?
|
223
277
|
|
224
278
|
# rename Grape's 'values' to 'enum'
|
225
279
|
select_values = p.delete(:values)
|
@@ -324,6 +378,7 @@ module GrapeSwagger
|
|
324
378
|
base_path: nil,
|
325
379
|
api_version: '0.1',
|
326
380
|
markdown: nil,
|
381
|
+
i18n_scope: :api,
|
327
382
|
hide_documentation_path: false,
|
328
383
|
hide_format: false,
|
329
384
|
format: nil,
|
@@ -339,7 +394,7 @@ module GrapeSwagger
|
|
339
394
|
|
340
395
|
target_class = options[:target_class]
|
341
396
|
@@mount_path = options[:mount_path]
|
342
|
-
@@class_name = options[:class_name] || options[:mount_path].
|
397
|
+
@@class_name = options[:class_name] || options[:mount_path].delete('/')
|
343
398
|
@@markdown = options[:markdown] ? GrapeSwagger::Markdown.new(options[:markdown]) : nil
|
344
399
|
@@hide_format = options[:hide_format]
|
345
400
|
api_version = options[:api_version]
|
@@ -349,6 +404,7 @@ module GrapeSwagger
|
|
349
404
|
api_doc = options[:api_documentation].dup
|
350
405
|
specific_api_doc = options[:specific_api_documentation].dup
|
351
406
|
@@models = options[:models] || []
|
407
|
+
i18n_scope = options[:i18n_scope]
|
352
408
|
|
353
409
|
@@hide_documentation_path = options[:hide_documentation_path]
|
354
410
|
|
@@ -361,7 +417,11 @@ module GrapeSwagger
|
|
361
417
|
@@documentation_class = self
|
362
418
|
|
363
419
|
desc api_doc.delete(:desc), api_doc
|
420
|
+
params do
|
421
|
+
optional :locale, type: Symbol, desc: 'Locale of API documentation'
|
422
|
+
end
|
364
423
|
get @@mount_path do
|
424
|
+
I18n.locale = params[:locale] || I18n.default_locale
|
365
425
|
header['Access-Control-Allow-Origin'] = '*'
|
366
426
|
header['Access-Control-Request-Method'] = '*'
|
367
427
|
|
@@ -375,14 +435,23 @@ module GrapeSwagger
|
|
375
435
|
namespace_routes_array = namespace_routes.keys.map do |local_route|
|
376
436
|
next if namespace_routes[local_route].map(&:route_hidden).all? { |value| value.respond_to?(:call) ? value.call : value }
|
377
437
|
|
378
|
-
url_format
|
438
|
+
url_format = '.{format}' unless @@hide_format
|
439
|
+
url_locale = "?locale=#{params[:locale]}" unless params[:locale].blank?
|
379
440
|
|
380
441
|
original_namespace_name = target_class.combined_namespace_identifiers.key?(local_route) ? target_class.combined_namespace_identifiers[local_route] : local_route
|
381
442
|
description = namespaces[original_namespace_name] && namespaces[original_namespace_name].options[:desc]
|
382
443
|
description ||= "Operations about #{original_namespace_name.pluralize}"
|
444
|
+
description = @@documentation_class.translate(
|
445
|
+
description, i18n_scope,
|
446
|
+
[
|
447
|
+
:"#{original_namespace_name}.desc",
|
448
|
+
:"#{original_namespace_name}.description"
|
449
|
+
],
|
450
|
+
namespace: original_namespace_name.pluralize
|
451
|
+
)
|
383
452
|
|
384
453
|
{
|
385
|
-
path: "/#{local_route}#{url_format}",
|
454
|
+
path: "/#{local_route}#{url_format}#{url_locale}",
|
386
455
|
description: description
|
387
456
|
}
|
388
457
|
end.compact
|
@@ -392,7 +461,7 @@ module GrapeSwagger
|
|
392
461
|
swaggerVersion: '1.2',
|
393
462
|
produces: @@documentation_class.content_types_for(target_class),
|
394
463
|
apis: namespace_routes_array,
|
395
|
-
info: @@documentation_class.parse_info(extra_info)
|
464
|
+
info: @@documentation_class.parse_info(extra_info, scope: i18n_scope)
|
396
465
|
}
|
397
466
|
|
398
467
|
output[:authorizations] = authorizations unless authorizations.nil? || authorizations.empty?
|
@@ -403,13 +472,15 @@ module GrapeSwagger
|
|
403
472
|
desc specific_api_doc.delete(:desc), { params:
|
404
473
|
specific_api_doc.delete(:params) || {} }.merge(specific_api_doc)
|
405
474
|
params do
|
475
|
+
optional :locale, type: Symbol, desc: 'Locale of API documentation'
|
406
476
|
requires :name, type: String, desc: 'Resource name of mounted API'
|
407
477
|
end
|
408
478
|
get "#{@@mount_path}/:name" do
|
479
|
+
I18n.locale = params[:locale] || I18n.default_locale
|
409
480
|
header['Access-Control-Allow-Origin'] = '*'
|
410
481
|
header['Access-Control-Request-Method'] = '*'
|
411
482
|
|
412
|
-
models =
|
483
|
+
models = Set.new(@@models.dup)
|
413
484
|
routes = target_class.combined_namespace_routes[params[:name]]
|
414
485
|
error!('Not Found', 404) unless routes
|
415
486
|
|
@@ -427,22 +498,33 @@ module GrapeSwagger
|
|
427
498
|
|
428
499
|
ops.each do |path, op_routes|
|
429
500
|
operations = op_routes.map do |route|
|
430
|
-
|
501
|
+
endpoint = target_class.endpoint_mapping[route.to_s.sub('(.:format)', '')]
|
502
|
+
endpoint_path = endpoint.options[:path] unless endpoint.nil?
|
503
|
+
i18n_key = [route.route_namespace, endpoint_path, route.route_method.downcase].flatten.join('/')
|
504
|
+
i18n_key = i18n_key.split('/').reject(&:empty?).join('.')
|
505
|
+
|
506
|
+
summary = @@documentation_class.translate(
|
507
|
+
route.route_description, i18n_scope,
|
508
|
+
[:"#{i18n_key}.desc", :"#{i18n_key}.description"]
|
509
|
+
)
|
510
|
+
notes = @@documentation_class.translate(
|
511
|
+
route.route_detail || route.route_notes, i18n_scope,
|
512
|
+
[:"#{i18n_key}.detail", :"#{i18n_key}.notes"]
|
513
|
+
)
|
514
|
+
notes = @@documentation_class.as_markdown(notes)
|
431
515
|
|
432
516
|
http_codes = @@documentation_class.parse_http_codes(route.route_http_codes, models)
|
433
517
|
|
434
|
-
models
|
435
|
-
|
436
|
-
models |= Array(route.route_entity) if route.route_entity.present?
|
437
|
-
|
438
|
-
models = @@documentation_class.models_with_included_presenters(models.flatten.compact)
|
518
|
+
models.merge(Array(route.route_entity)) if route.route_entity.present?
|
439
519
|
|
440
520
|
operation = {
|
441
521
|
notes: notes.to_s,
|
442
|
-
summary:
|
522
|
+
summary: summary,
|
443
523
|
nickname: route.route_nickname || (route.route_method + route.route_path.gsub(/[\/:\(\)\.]/, '-')),
|
444
524
|
method: route.route_method,
|
445
|
-
parameters: @@documentation_class.parse_header_params(route.route_headers
|
525
|
+
parameters: @@documentation_class.parse_header_params(route.route_headers, scope: i18n_scope, key: i18n_key) +
|
526
|
+
@@documentation_class.parse_params(route.route_params, route.route_path, route.route_method,
|
527
|
+
scope: i18n_scope, key: i18n_key),
|
446
528
|
type: route.route_is_array ? 'array' : 'void'
|
447
529
|
}
|
448
530
|
operation[:authorizations] = route.route_authorizations unless route.route_authorizations.nil? || route.route_authorizations.empty?
|
@@ -469,6 +551,8 @@ module GrapeSwagger
|
|
469
551
|
}
|
470
552
|
end
|
471
553
|
|
554
|
+
models = @@documentation_class.models_with_included_presenters(models.to_a.flatten.compact)
|
555
|
+
|
472
556
|
# use custom resource naming if available
|
473
557
|
if target_class.combined_namespace_identifiers.key? params[:name]
|
474
558
|
resource_path = target_class.combined_namespace_identifiers[params[:name]]
|
@@ -485,7 +569,7 @@ module GrapeSwagger
|
|
485
569
|
|
486
570
|
base_path = @@documentation_class.parse_base_path(options[:base_path], request)
|
487
571
|
api_description[:basePath] = base_path if base_path && base_path.size > 0 && root_base_path != false
|
488
|
-
api_description[:models] = @@documentation_class.parse_entity_models(models) unless models.empty?
|
572
|
+
api_description[:models] = @@documentation_class.parse_entity_models(models, scope: i18n_scope) unless models.empty?
|
489
573
|
api_description[:authorizations] = authorizations if authorizations
|
490
574
|
|
491
575
|
api_description
|