sober_swag 0.15.0 → 0.20.0
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/.github/dependabot.yml +15 -0
- data/.github/workflows/lint.yml +4 -9
- data/.github/workflows/ruby.yml +2 -6
- data/.gitignore +4 -0
- data/.rubocop.yml +50 -5
- data/.yardopts +7 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile +8 -0
- data/README.md +155 -4
- data/bin/rspec +29 -0
- data/docs/serializers.md +18 -13
- data/example/Gemfile +2 -2
- data/example/app/controllers/people_controller.rb +4 -0
- data/example/app/controllers/posts_controller.rb +5 -0
- data/example/config/environments/production.rb +1 -1
- data/lib/sober_swag.rb +6 -1
- data/lib/sober_swag/compiler.rb +29 -3
- data/lib/sober_swag/compiler/path.rb +49 -3
- data/lib/sober_swag/compiler/paths.rb +20 -0
- data/lib/sober_swag/compiler/primitive.rb +20 -1
- data/lib/sober_swag/compiler/type.rb +105 -22
- data/lib/sober_swag/controller.rb +42 -15
- data/lib/sober_swag/controller/route.rb +133 -28
- data/lib/sober_swag/input_object.rb +117 -7
- data/lib/sober_swag/nodes/array.rb +19 -0
- data/lib/sober_swag/nodes/attribute.rb +45 -4
- data/lib/sober_swag/nodes/base.rb +27 -7
- data/lib/sober_swag/nodes/binary.rb +30 -13
- data/lib/sober_swag/nodes/enum.rb +16 -1
- data/lib/sober_swag/nodes/list.rb +20 -0
- data/lib/sober_swag/nodes/nullable_primitive.rb +3 -0
- data/lib/sober_swag/nodes/object.rb +4 -1
- data/lib/sober_swag/nodes/one_of.rb +11 -3
- data/lib/sober_swag/nodes/primitive.rb +34 -2
- data/lib/sober_swag/nodes/sum.rb +8 -0
- data/lib/sober_swag/output_object.rb +35 -4
- data/lib/sober_swag/output_object/definition.rb +31 -1
- data/lib/sober_swag/output_object/field.rb +31 -11
- data/lib/sober_swag/output_object/field_syntax.rb +19 -3
- data/lib/sober_swag/output_object/view.rb +46 -1
- data/lib/sober_swag/parser.rb +7 -1
- data/lib/sober_swag/serializer/array.rb +27 -3
- data/lib/sober_swag/serializer/base.rb +75 -25
- data/lib/sober_swag/serializer/conditional.rb +33 -1
- data/lib/sober_swag/serializer/field_list.rb +18 -2
- data/lib/sober_swag/serializer/mapped.rb +10 -1
- data/lib/sober_swag/serializer/optional.rb +18 -1
- data/lib/sober_swag/serializer/primitive.rb +3 -0
- data/lib/sober_swag/server.rb +27 -11
- data/lib/sober_swag/type/named.rb +14 -0
- data/lib/sober_swag/types/comma_array.rb +4 -0
- data/lib/sober_swag/version.rb +1 -1
- data/sober_swag.gemspec +2 -2
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97cb4bbfd84f28f6f79368c3f78182835217868a1d3142c38107ab3b03552952
|
4
|
+
data.tar.gz: 1cd8446250a8ddadc16eb114a773b9d317c2182e2bcb8c692c59681331ef972b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6b055ea451db16f12a02ebe2bc6da459aefcf13605a54f4f0b0cff8aa694b73e2c4cb2c2f759a89c859a820a74a37391728998e0939a770cda2783c2190586e
|
7
|
+
data.tar.gz: 3a49c153297750447c2776b086da135b81c80a1b628780d9a7ab6f68f204ddeaa3b21e08ffd02f8a49e92f1a7ac5942b0e42d295307299e8623ebb6a765731dd
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
3
|
+
# Please see the documentation for all configuration options:
|
4
|
+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
5
|
+
|
6
|
+
version: 2
|
7
|
+
updates:
|
8
|
+
- package-ecosystem: "bundler"
|
9
|
+
directory: "/"
|
10
|
+
schedule:
|
11
|
+
interval: "daily"
|
12
|
+
- package-ecosystem: "bundler"
|
13
|
+
directory: "/example"
|
14
|
+
schedule:
|
15
|
+
interval: "daily"
|
data/.github/workflows/lint.yml
CHANGED
@@ -19,17 +19,14 @@ jobs:
|
|
19
19
|
runs-on: ubuntu-latest
|
20
20
|
strategy:
|
21
21
|
matrix:
|
22
|
-
ruby: [ '2.6', '2.7' ]
|
22
|
+
ruby: [ '2.6', '2.7', '3.0' ]
|
23
23
|
|
24
24
|
steps:
|
25
25
|
- uses: actions/checkout@v2
|
26
26
|
- name: Set up Ruby
|
27
|
-
|
28
|
-
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
|
-
# uses: ruby/setup-ruby@v1
|
30
|
-
uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
|
27
|
+
uses: ruby/setup-ruby@v1
|
31
28
|
with:
|
32
|
-
ruby-version:
|
29
|
+
ruby-version: ${{ matrix.ruby }}
|
33
30
|
- uses: actions/cache@v2
|
34
31
|
with:
|
35
32
|
path: vendor/bundle
|
@@ -40,10 +37,8 @@ jobs:
|
|
40
37
|
run: |
|
41
38
|
bundle config path vendor/bundle
|
42
39
|
bundle install
|
43
|
-
gem install rubocop
|
44
|
-
gem install rubocop-rspec
|
45
40
|
- name: Run Lints
|
46
|
-
run:
|
41
|
+
run: bundle exec rubocop -P
|
47
42
|
- uses: actions/cache@v2
|
48
43
|
with:
|
49
44
|
path: example/vendor/bundle
|
data/.github/workflows/ruby.yml
CHANGED
@@ -19,15 +19,11 @@ jobs:
|
|
19
19
|
runs-on: ubuntu-latest
|
20
20
|
strategy:
|
21
21
|
matrix:
|
22
|
-
ruby: [ '2.6', '2.7' ]
|
23
|
-
|
22
|
+
ruby: [ '2.6', '2.7', '3.0' ]
|
24
23
|
steps:
|
25
24
|
- uses: actions/checkout@v2
|
26
25
|
- name: Set up Ruby
|
27
|
-
|
28
|
-
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
|
-
# uses: ruby/setup-ruby@v1
|
30
|
-
uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
|
26
|
+
uses: ruby/setup-ruby@v1
|
31
27
|
with:
|
32
28
|
ruby-version: ${{ matrix.ruby }}
|
33
29
|
- uses: actions/cache@v2
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,85 +1,130 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Style/BlockDelimiters:
|
4
|
-
EnforcedStyle: braces_for_chaining
|
1
|
+
require: rubocop-rspec
|
2
|
+
|
5
3
|
AllCops:
|
6
4
|
TargetRubyVersion: 2.6.0
|
5
|
+
NewCops: enable
|
7
6
|
Exclude:
|
8
7
|
- 'bin/bundle'
|
9
8
|
- 'example/bin/bundle'
|
9
|
+
- 'vendor/bundle/**/*'
|
10
10
|
|
11
11
|
Layout/LineLength:
|
12
12
|
Max: 160
|
13
|
-
|
13
|
+
|
14
14
|
RSpec/NamedSubject:
|
15
15
|
Enabled: false
|
16
|
+
|
16
17
|
RSpec/DescribeClass:
|
17
18
|
Enabled: false
|
19
|
+
|
18
20
|
Metrics/BlockLength:
|
19
21
|
Exclude:
|
20
22
|
- 'spec/**/*.rb'
|
21
23
|
- 'sober_swag.gemspec'
|
22
24
|
- 'example/spec/**/*.rb'
|
25
|
+
|
26
|
+
Lint/MissingSuper:
|
27
|
+
Enabled: false
|
28
|
+
|
23
29
|
RSpec/ImplicitBlockExpectation:
|
24
30
|
Enabled: false
|
31
|
+
|
25
32
|
RSpec/ImplicitExpect:
|
26
33
|
EnforcedStyle: should
|
34
|
+
|
27
35
|
RSpec/LeadingSubject:
|
28
36
|
Enabled: false
|
37
|
+
|
29
38
|
Style/MultilineBlockChain:
|
30
39
|
Enabled: false
|
40
|
+
|
31
41
|
Metrics/AbcSize:
|
32
42
|
Enabled: false
|
43
|
+
|
33
44
|
Style/Documentation:
|
34
45
|
Exclude:
|
35
46
|
- 'example/db/migrate/**/*'
|
47
|
+
|
36
48
|
Metrics/PerceivedComplexity:
|
37
49
|
Enabled: false
|
50
|
+
|
38
51
|
Layout/EmptyLinesAroundAttributeAccessor:
|
39
52
|
Enabled: true
|
53
|
+
|
40
54
|
Layout/SpaceAroundMethodCallOperator:
|
41
55
|
Enabled: true
|
56
|
+
|
42
57
|
Lint/DeprecatedOpenSSLConstant:
|
43
58
|
Enabled: true
|
59
|
+
|
44
60
|
Lint/DuplicateElsifCondition:
|
45
61
|
Enabled: true
|
62
|
+
|
46
63
|
Lint/MixedRegexpCaptureTypes:
|
47
64
|
Enabled: true
|
65
|
+
|
48
66
|
Lint/RaiseException:
|
49
67
|
Enabled: true
|
68
|
+
|
50
69
|
Lint/StructNewOverride:
|
51
70
|
Enabled: true
|
71
|
+
|
52
72
|
Style/AccessorGrouping:
|
53
73
|
Enabled: true
|
74
|
+
|
54
75
|
Style/ArrayCoercion:
|
55
76
|
Enabled: true
|
77
|
+
|
56
78
|
Style/BisectedAttrAccessor:
|
57
79
|
Enabled: true
|
80
|
+
|
58
81
|
Style/CaseLikeIf:
|
59
82
|
Enabled: true
|
83
|
+
|
60
84
|
Style/ExponentialNotation:
|
61
85
|
Enabled: true
|
86
|
+
|
62
87
|
Style/HashAsLastArrayItem:
|
63
88
|
Enabled: true
|
89
|
+
|
64
90
|
Style/HashEachMethods:
|
65
91
|
Enabled: true
|
92
|
+
|
66
93
|
Style/HashLikeCase:
|
67
94
|
Enabled: true
|
95
|
+
|
68
96
|
Style/HashTransformKeys:
|
69
97
|
Enabled: true
|
98
|
+
|
70
99
|
Style/HashTransformValues:
|
71
100
|
Enabled: true
|
101
|
+
|
72
102
|
Style/RedundantAssignment:
|
73
103
|
Enabled: true
|
104
|
+
|
74
105
|
Style/RedundantFetchBlock:
|
75
106
|
Enabled: true
|
107
|
+
|
76
108
|
Style/RedundantFileExtensionInRequire:
|
77
109
|
Enabled: true
|
110
|
+
|
78
111
|
Style/RedundantRegexpCharacterClass:
|
79
112
|
Enabled: true
|
113
|
+
|
80
114
|
Style/RedundantRegexpEscape:
|
81
115
|
Enabled: true
|
116
|
+
|
82
117
|
Style/SlicingWithRange:
|
83
118
|
Enabled: true
|
119
|
+
|
84
120
|
RSpec/NestedGroups:
|
85
121
|
Max: 5
|
122
|
+
|
123
|
+
RSpec/ExampleLength:
|
124
|
+
Max: 10
|
125
|
+
|
126
|
+
Style/FrozenStringLiteralComment:
|
127
|
+
Enabled: false
|
128
|
+
|
129
|
+
Style/BlockDelimiters:
|
130
|
+
EnforcedStyle: braces_for_chaining
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,30 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
##
|
3
|
+
## [v0.20.0] 2021-05-17
|
4
4
|
|
5
|
+
- Added YARD documentation to almost every method
|
6
|
+
- Added `except` parameter to the `merge` method, which allows a specified field to be excluded from the merge.
|
7
|
+
|
8
|
+
## [v0.19.0] 2021-03-10
|
9
|
+
|
10
|
+
- Use [redoc](https://github.com/Redocly/redoc) for generated documentation UI
|
11
|
+
|
12
|
+
## [v0.18.0] 2021-03-02
|
13
|
+
|
14
|
+
- Add generic hash type for primitive types
|
15
|
+
|
16
|
+
## [v0.17.0]: 2020-11-30
|
17
|
+
|
18
|
+
- Allow tagging endpoints via the new `tags` method.
|
19
|
+
|
20
|
+
## [v0.16.0]: 2020-10-23
|
21
|
+
|
22
|
+
- Allow non-class types to be used as the inputs to controllers
|
23
|
+
|
24
|
+
## [v0.15.0]: 2020-09-02
|
25
|
+
|
26
|
+
### Added
|
27
|
+
- Add a new `#merge` method to output objects, which will merge fields from another output object into the given output object.
|
5
28
|
- Add `multi` to Output Objects, as a way to define more than one field of the same type at once.
|
6
29
|
- Add an `inherits:` key to output objects, for view inheritance.
|
7
30
|
- Add `SoberSwag::Types::CommaArray`, which parses comma-separated strings into arrays.
|
@@ -9,3 +32,8 @@
|
|
9
32
|
This class is mostly useful for query parameters where you want a simpler format: `tag=foo,bar` instead of `tag[]=foo,tag[]=bar`.
|
10
33
|
- Add support for using `meta` to specify alternative `style` and `explode` keys for query and path params.
|
11
34
|
Note that this support *does not* extend to parsing: If you modify the `style` or `explode` keywords, you will need to make those input formats work with the actual type yourself.
|
35
|
+
|
36
|
+
### Fixed
|
37
|
+
- No longer swallow `Dry::Struct` errors, instead let them surface to the user.
|
38
|
+
|
39
|
+
[v0.15.0]: https://github.com/SonderMindOrg/sober_swag/releases/tag/v0.15.0
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,10 @@ This generates documentation from *types*, which (conveniently) also lets you ge
|
|
9
9
|
|
10
10
|
An introductory presentation is available [here](https://www.icloud.com/keynote/0bxP3Dn8ETNO0lpsSQSVfEL6Q#SoberSwagPresentation).
|
11
11
|
|
12
|
+
Further documentation on using the gem is available in the `docs/` directory:
|
13
|
+
|
14
|
+
- {file:docs/serializers.md Serializers}
|
15
|
+
|
12
16
|
## Types for a fully-automated API
|
13
17
|
|
14
18
|
SoberSwag lets you type your API using describe blocks.
|
@@ -18,7 +22,14 @@ This lets you type your API endpoint:
|
|
18
22
|
```ruby
|
19
23
|
class PeopleController < ApplicationController
|
20
24
|
include SoberSwag::Controller
|
25
|
+
|
21
26
|
define :patch, :update, '/people/{id}' do
|
27
|
+
summary 'Update a Person record.'
|
28
|
+
description <<~MARKDOWN
|
29
|
+
You can use this endpoint to update a Person record. Note that age cannot
|
30
|
+
be a negative integer.
|
31
|
+
MARKDOWN
|
32
|
+
|
22
33
|
query_params do
|
23
34
|
attribute? :include_extra_info, Types::Params::Bool
|
24
35
|
end
|
@@ -28,11 +39,13 @@ class PeopleController < ApplicationController
|
|
28
39
|
end
|
29
40
|
path_params { attribute :id, Types::Params::Integer }
|
30
41
|
end
|
42
|
+
def update
|
43
|
+
# update action here
|
44
|
+
end
|
31
45
|
end
|
32
46
|
```
|
33
47
|
|
34
|
-
|
35
|
-
More than that, we can use this information *inside* our controller methods:
|
48
|
+
Then we can use the information from our SoberSwag definition *inside* the controller method:
|
36
49
|
|
37
50
|
```ruby
|
38
51
|
def update
|
@@ -44,6 +57,51 @@ end
|
|
44
57
|
No need for `params.require` or anything like that.
|
45
58
|
You define the type of parameters you accept, and we reject anything that doesn't fit.
|
46
59
|
|
60
|
+
### Rendering Swagger documentation from SoberSwag
|
61
|
+
|
62
|
+
We can also use the information from SoberSwag objects to generate Swagger
|
63
|
+
documentation, available at the `swagger` action on this controller.
|
64
|
+
|
65
|
+
You can create the `swagger` action for a controller as follows:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# config/routes.rb
|
69
|
+
Rails.application.routes.draw do
|
70
|
+
# Add a `swagger` GET endpoint to render the Swagger documentation created
|
71
|
+
# by SoberSwag.
|
72
|
+
resources :people do
|
73
|
+
get :swagger, on: :collection
|
74
|
+
end
|
75
|
+
|
76
|
+
# Or use a concern to make it easier to enable swagger endpoints for a number
|
77
|
+
# of controllers at once.
|
78
|
+
concern :swaggerable do
|
79
|
+
get :swagger, on: :collection
|
80
|
+
end
|
81
|
+
|
82
|
+
resources :people, concerns: :swaggerable do
|
83
|
+
get :search, on: :collection
|
84
|
+
end
|
85
|
+
|
86
|
+
resources :places, only: [:index], concerns: :swaggerable
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
If you don't want the API documentation to show up in certain cases, you can
|
91
|
+
use an environment variable or a check on the current Rails environment.
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
# config/routes.rb
|
95
|
+
Rails.application.routes.draw do
|
96
|
+
resources :people do
|
97
|
+
# Enable based on environment variable.
|
98
|
+
get :swagger, on: :collection if ENV['ENABLE_SWAGGER']
|
99
|
+
# Or just disable in production.
|
100
|
+
get :swagger, on: :collection unless Rails.env.production?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
47
105
|
### Typed Responses
|
48
106
|
|
49
107
|
Want to go further and type your responses too?
|
@@ -53,6 +111,8 @@ Use SoberSwag output objects, a serializer library heavily inspired by [Blueprin
|
|
53
111
|
PersonOutputObject = SoberSwag::OutputObject.define do
|
54
112
|
field :id, primitive(:Integer)
|
55
113
|
field :name, primitive(:String).optional
|
114
|
+
# For fields that don't map to a simple attribute on your model, you can
|
115
|
+
# use a block.
|
56
116
|
field :is_registered, primitive(:Bool) do |person|
|
57
117
|
person.registered?
|
58
118
|
end
|
@@ -95,7 +155,7 @@ User = SoberSwag.input_object do
|
|
95
155
|
attribute :name, SoberSwag::Types::String
|
96
156
|
# use ? if attributes are not required
|
97
157
|
attribute? :favorite_movie, SoberSwag::Types::String
|
98
|
-
# use .optional if attributes may be
|
158
|
+
# use .optional if attributes may be nil
|
99
159
|
attribute :age, SoberSwag::Types::Params::Integer.optional
|
100
160
|
end
|
101
161
|
```
|
@@ -120,6 +180,63 @@ end
|
|
120
180
|
Under the hood, this literally just generates a subclass of `Dry::Struct`.
|
121
181
|
We use the DSL-like method just to make working with Rails' reloading less annoying.
|
122
182
|
|
183
|
+
#### Nested object attributes
|
184
|
+
|
185
|
+
You can nest attributes using a block. They'll return as nested JSON objects.
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
User = SoberSwag.input_object do
|
189
|
+
attribute :user_notes do
|
190
|
+
attribute :note, SoberSwag::Types::String
|
191
|
+
end
|
192
|
+
end
|
193
|
+
```
|
194
|
+
|
195
|
+
If you want to use a specific type of object within an input object, you can
|
196
|
+
nest them by setting the other input object as the type of an attribute. For
|
197
|
+
example, if you had a UserGroup object with various Users, you could write
|
198
|
+
them like this:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
User = SoberSwag.input_object do
|
202
|
+
attribute :name, SoberSwag::Types::String
|
203
|
+
attribute :age, SoberSwag::Types::Params::Integer.optional
|
204
|
+
end
|
205
|
+
|
206
|
+
UserGroup = SoberSwag.input_object do
|
207
|
+
attribute :name, SoberSwag::Types::String
|
208
|
+
attribute :users, SoberSwag::Types::Array.of(User)
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
#### Input and Output Object Identifiers
|
213
|
+
|
214
|
+
Both input objects and output objects accept an identifier, which is used in
|
215
|
+
the Swagger Documentation to disambiguate between SoberSwag types.
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
User = SoberSwag.input_object do
|
219
|
+
identifier 'User'
|
220
|
+
|
221
|
+
attribute? :name, SoberSwag::Types::String
|
222
|
+
end
|
223
|
+
```
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
PersonOutputObject = SoberSwag::OutputObject.define do
|
227
|
+
identifier 'PersonOutput'
|
228
|
+
|
229
|
+
field :id, primitive(:Integer)
|
230
|
+
field :name, primitive(:String).optional
|
231
|
+
end
|
232
|
+
```
|
233
|
+
|
234
|
+
You can use these to make your Swagger documentation a bit easier to follow,
|
235
|
+
and it can also be useful for 'namespacing' objects if you're developing in
|
236
|
+
a large application, e.g. if you had a pet store and for some reason users
|
237
|
+
with cats and users with dogs were different, you could namespace it with
|
238
|
+
`identifier 'Dogs.User'`.
|
239
|
+
|
123
240
|
#### Adding additional documentation
|
124
241
|
|
125
242
|
You can use the `.meta` attribute on a type to add additional documentation.
|
@@ -151,10 +268,44 @@ QueryInput = SoberSwag.input_object do
|
|
151
268
|
end
|
152
269
|
```
|
153
270
|
|
271
|
+
## Tags
|
272
|
+
|
273
|
+
If you want to organize your API into sections, you can use `tags`.
|
274
|
+
It's quite simple:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
define :patch, :update, '/people/{id}' do
|
278
|
+
# other cool config
|
279
|
+
tags 'people', 'mutations', 'incurs_cost'
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
283
|
+
This will map to OpenAPI's `tags` field (naturally), and the UI codegen will automatically organize your endpoints by their tags.
|
284
|
+
|
285
|
+
## Testing the validity of output objects
|
286
|
+
|
287
|
+
If you're using RSpec and want to test the validity of output objects, you can do so relatively easily.
|
288
|
+
|
289
|
+
For example, assuming that you have a `UserOutputObject` class for representing a User record, and you have a `:user` factory via FactoryBot, you can validate that the serialization works without error like so:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
RSpec.describe UserOutputObject do
|
293
|
+
describe 'serialized result' do
|
294
|
+
subject do
|
295
|
+
described_class.type.new(described_class.serialize(create(:user)))
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'works with an object' do
|
299
|
+
expect { subject }.not_to raise_error
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
```
|
304
|
+
|
154
305
|
## Special Thanks
|
155
306
|
|
156
307
|
This gem is a mishmash of ideas from various sources.
|
157
308
|
The biggest thanks is owed to the [dry-rb](https://github.com/dry-rb) project, upon which the typing of SoberSwag is based.
|
158
309
|
On an API design level, much is owed to [blueprinter](https://github.com/procore/blueprinter) for the serializers.
|
159
310
|
The idea of a strongly-typed API came from the Haskell framework [servant](https://www.servant.dev/).
|
160
|
-
Generating the swagger
|
311
|
+
Generating the swagger documentation happens via the use of a catamorphism, which I believe I first really understood thanks to [this medium article by Jared Tobin](https://medium.com/@jaredtobin/practical-recursion-schemes-c10648ec1c29).
|