grape-swagger 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
[](http://badge.fury.io/rb/grape-swagger)
|
4
4
|
[](https://travis-ci.org/ruby-grape/grape-swagger)
|
5
|
+
[](https://gemnasium.com/ruby-grape/grape-swagger)
|
5
6
|
[](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
|