sober_swag 0.1.0 → 0.6.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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/config/rubocop_linter_action.yml +4 -0
  3. data/.github/workflows/lint.yml +15 -0
  4. data/.github/workflows/ruby.yml +33 -2
  5. data/.gitignore +4 -0
  6. data/.rubocop.yml +75 -1
  7. data/.ruby-version +1 -1
  8. data/README.md +154 -1
  9. data/bin/console +16 -15
  10. data/docs/serializers.md +203 -0
  11. data/example/.rspec +1 -0
  12. data/example/.ruby-version +1 -1
  13. data/example/Gemfile +9 -7
  14. data/example/Gemfile.lock +96 -79
  15. data/example/app/controllers/people_controller.rb +41 -23
  16. data/example/app/controllers/posts_controller.rb +110 -0
  17. data/example/app/models/application_record.rb +3 -0
  18. data/example/app/models/person.rb +6 -0
  19. data/example/app/models/post.rb +9 -0
  20. data/example/app/output_objects/person_errors_output_object.rb +5 -0
  21. data/example/app/output_objects/person_output_object.rb +15 -0
  22. data/example/app/output_objects/post_output_object.rb +10 -0
  23. data/example/bin/bundle +24 -20
  24. data/example/bin/rails +1 -1
  25. data/example/bin/rake +1 -1
  26. data/example/config/application.rb +11 -7
  27. data/example/config/environments/development.rb +0 -1
  28. data/example/config/environments/production.rb +3 -3
  29. data/example/config/puma.rb +5 -5
  30. data/example/config/routes.rb +3 -0
  31. data/example/config/spring.rb +4 -4
  32. data/example/db/migrate/20200311152021_create_people.rb +0 -1
  33. data/example/db/migrate/20200603172347_create_posts.rb +11 -0
  34. data/example/db/schema.rb +16 -7
  35. data/example/spec/rails_helper.rb +64 -0
  36. data/example/spec/requests/people/create_spec.rb +52 -0
  37. data/example/spec/requests/people/get_spec.rb +35 -0
  38. data/example/spec/requests/people/index_spec.rb +69 -0
  39. data/example/spec/spec_helper.rb +94 -0
  40. data/lib/sober_swag.rb +6 -3
  41. data/lib/sober_swag/compiler/error.rb +2 -0
  42. data/lib/sober_swag/compiler/path.rb +2 -5
  43. data/lib/sober_swag/compiler/paths.rb +0 -1
  44. data/lib/sober_swag/compiler/type.rb +86 -56
  45. data/lib/sober_swag/controller.rb +16 -11
  46. data/lib/sober_swag/controller/route.rb +18 -21
  47. data/lib/sober_swag/controller/undefined_body_error.rb +3 -0
  48. data/lib/sober_swag/controller/undefined_path_error.rb +3 -0
  49. data/lib/sober_swag/controller/undefined_query_error.rb +3 -0
  50. data/lib/sober_swag/input_object.rb +28 -0
  51. data/lib/sober_swag/nodes/array.rb +1 -1
  52. data/lib/sober_swag/nodes/base.rb +5 -3
  53. data/lib/sober_swag/nodes/binary.rb +2 -1
  54. data/lib/sober_swag/nodes/enum.rb +4 -2
  55. data/lib/sober_swag/nodes/list.rb +0 -1
  56. data/lib/sober_swag/nodes/primitive.rb +6 -5
  57. data/lib/sober_swag/output_object.rb +102 -0
  58. data/lib/sober_swag/output_object/definition.rb +30 -0
  59. data/lib/sober_swag/{blueprint → output_object}/field.rb +14 -4
  60. data/lib/sober_swag/{blueprint → output_object}/field_syntax.rb +2 -2
  61. data/lib/sober_swag/{blueprint → output_object}/view.rb +15 -6
  62. data/lib/sober_swag/parser.rb +9 -4
  63. data/lib/sober_swag/serializer.rb +5 -2
  64. data/lib/sober_swag/serializer/array.rb +12 -0
  65. data/lib/sober_swag/serializer/base.rb +50 -1
  66. data/lib/sober_swag/serializer/conditional.rb +19 -2
  67. data/lib/sober_swag/serializer/field_list.rb +29 -6
  68. data/lib/sober_swag/serializer/mapped.rb +15 -3
  69. data/lib/sober_swag/serializer/meta.rb +35 -0
  70. data/lib/sober_swag/serializer/optional.rb +17 -2
  71. data/lib/sober_swag/serializer/primitive.rb +4 -1
  72. data/lib/sober_swag/server.rb +83 -0
  73. data/lib/sober_swag/types.rb +3 -0
  74. data/lib/sober_swag/version.rb +1 -1
  75. data/sober_swag.gemspec +8 -4
  76. metadata +79 -47
  77. data/Gemfile.lock +0 -92
  78. data/example/person.json +0 -4
  79. data/example/test/controllers/.keep +0 -0
  80. data/example/test/fixtures/.keep +0 -0
  81. data/example/test/fixtures/files/.keep +0 -0
  82. data/example/test/fixtures/people.yml +0 -11
  83. data/example/test/integration/.keep +0 -0
  84. data/example/test/models/.keep +0 -0
  85. data/example/test/models/person_test.rb +0 -7
  86. data/example/test/test_helper.rb +0 -13
  87. data/lib/sober_swag/blueprint.rb +0 -113
  88. data/lib/sober_swag/path.rb +0 -8
  89. data/lib/sober_swag/path/integer.rb +0 -21
  90. data/lib/sober_swag/path/lit.rb +0 -41
  91. data/lib/sober_swag/path/literal.rb +0 -29
  92. data/lib/sober_swag/path/param.rb +0 -33
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -1 +1 @@
1
- 2.7.0
1
+ 2.6.5
@@ -1,14 +1,14 @@
1
1
  source 'https://rubygems.org'
2
2
  git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
3
 
4
- ruby '2.7.0'
5
-
6
4
  # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
7
- gem 'rails', '~> 6.0.2', '>= 6.0.2.1'
5
+ gem 'rails', '~> 6.0.2', '>= 6.0.2.2'
6
+
7
+ gem 'actionpack', '>= 6.0.3.2'
8
8
  # Use sqlite3 as the database for Active Record
9
9
  gem 'sqlite3', '~> 1.4'
10
10
  # Use Puma as the app server
11
- gem 'puma', '~> 4.1'
11
+ gem 'puma', '~> 4.3'
12
12
  # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
13
13
  # gem 'jbuilder', '~> 2.7'
14
14
  # Use Active Model has_secure_password
@@ -20,14 +20,16 @@ gem 'bootsnap', '>= 1.4.2', require: false
20
20
  # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
21
21
  # gem 'rack-cors'
22
22
 
23
- gem 'sober_swag', path: '..'
23
+ gem 'sober_swag', path: '..'
24
24
 
25
25
  group :development, :test do
26
26
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
27
- gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
27
+ gem 'byebug', platforms: %i[mri mingw x64_mingw]
28
28
 
29
29
  gem 'dry-types-rails'
30
30
 
31
+ gem 'rspec-rails'
32
+
31
33
  gem 'pry'
32
34
  end
33
35
 
@@ -39,4 +41,4 @@ group :development do
39
41
  end
40
42
 
41
43
  # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
42
- gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
44
+ gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- sober_swag (0.1.0)
4
+ sober_swag (0.5.0)
5
5
  activesupport
6
6
  dry-struct (~> 1.0)
7
7
  dry-types (~> 1.2)
@@ -9,69 +9,70 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- actioncable (6.0.2.1)
13
- actionpack (= 6.0.2.1)
12
+ actioncable (6.0.3.2)
13
+ actionpack (= 6.0.3.2)
14
14
  nio4r (~> 2.0)
15
15
  websocket-driver (>= 0.6.1)
16
- actionmailbox (6.0.2.1)
17
- actionpack (= 6.0.2.1)
18
- activejob (= 6.0.2.1)
19
- activerecord (= 6.0.2.1)
20
- activestorage (= 6.0.2.1)
21
- activesupport (= 6.0.2.1)
16
+ actionmailbox (6.0.3.2)
17
+ actionpack (= 6.0.3.2)
18
+ activejob (= 6.0.3.2)
19
+ activerecord (= 6.0.3.2)
20
+ activestorage (= 6.0.3.2)
21
+ activesupport (= 6.0.3.2)
22
22
  mail (>= 2.7.1)
23
- actionmailer (6.0.2.1)
24
- actionpack (= 6.0.2.1)
25
- actionview (= 6.0.2.1)
26
- activejob (= 6.0.2.1)
23
+ actionmailer (6.0.3.2)
24
+ actionpack (= 6.0.3.2)
25
+ actionview (= 6.0.3.2)
26
+ activejob (= 6.0.3.2)
27
27
  mail (~> 2.5, >= 2.5.4)
28
28
  rails-dom-testing (~> 2.0)
29
- actionpack (6.0.2.1)
30
- actionview (= 6.0.2.1)
31
- activesupport (= 6.0.2.1)
29
+ actionpack (6.0.3.2)
30
+ actionview (= 6.0.3.2)
31
+ activesupport (= 6.0.3.2)
32
32
  rack (~> 2.0, >= 2.0.8)
33
33
  rack-test (>= 0.6.3)
34
34
  rails-dom-testing (~> 2.0)
35
35
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
- actiontext (6.0.2.1)
37
- actionpack (= 6.0.2.1)
38
- activerecord (= 6.0.2.1)
39
- activestorage (= 6.0.2.1)
40
- activesupport (= 6.0.2.1)
36
+ actiontext (6.0.3.2)
37
+ actionpack (= 6.0.3.2)
38
+ activerecord (= 6.0.3.2)
39
+ activestorage (= 6.0.3.2)
40
+ activesupport (= 6.0.3.2)
41
41
  nokogiri (>= 1.8.5)
42
- actionview (6.0.2.1)
43
- activesupport (= 6.0.2.1)
42
+ actionview (6.0.3.2)
43
+ activesupport (= 6.0.3.2)
44
44
  builder (~> 3.1)
45
45
  erubi (~> 1.4)
46
46
  rails-dom-testing (~> 2.0)
47
47
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
- activejob (6.0.2.1)
49
- activesupport (= 6.0.2.1)
48
+ activejob (6.0.3.2)
49
+ activesupport (= 6.0.3.2)
50
50
  globalid (>= 0.3.6)
51
- activemodel (6.0.2.1)
52
- activesupport (= 6.0.2.1)
53
- activerecord (6.0.2.1)
54
- activemodel (= 6.0.2.1)
55
- activesupport (= 6.0.2.1)
56
- activestorage (6.0.2.1)
57
- actionpack (= 6.0.2.1)
58
- activejob (= 6.0.2.1)
59
- activerecord (= 6.0.2.1)
51
+ activemodel (6.0.3.2)
52
+ activesupport (= 6.0.3.2)
53
+ activerecord (6.0.3.2)
54
+ activemodel (= 6.0.3.2)
55
+ activesupport (= 6.0.3.2)
56
+ activestorage (6.0.3.2)
57
+ actionpack (= 6.0.3.2)
58
+ activejob (= 6.0.3.2)
59
+ activerecord (= 6.0.3.2)
60
60
  marcel (~> 0.3.1)
61
- activesupport (6.0.2.1)
61
+ activesupport (6.0.3.2)
62
62
  concurrent-ruby (~> 1.0, >= 1.0.2)
63
63
  i18n (>= 0.7, < 2)
64
64
  minitest (~> 5.1)
65
65
  tzinfo (~> 1.1)
66
- zeitwerk (~> 2.2)
66
+ zeitwerk (~> 2.2, >= 2.2.2)
67
67
  bootsnap (1.4.6)
68
68
  msgpack (~> 1.0)
69
69
  builder (3.2.4)
70
- byebug (11.1.1)
71
- coderay (1.1.2)
70
+ byebug (11.1.3)
71
+ coderay (1.1.3)
72
72
  concurrent-ruby (1.1.6)
73
73
  crass (1.0.6)
74
- dry-configurable (0.11.3)
74
+ diff-lcs (1.4.4)
75
+ dry-configurable (0.11.6)
75
76
  concurrent-ruby (~> 1.0)
76
77
  dry-core (~> 0.4, >= 0.4.7)
77
78
  dry-equalizer (~> 0.2)
@@ -102,76 +103,93 @@ GEM
102
103
  dry-types (>= 0.8.1)
103
104
  rails (>= 3)
104
105
  erubi (1.9.0)
105
- ffi (1.12.2)
106
+ ffi (1.13.1)
106
107
  globalid (0.4.2)
107
108
  activesupport (>= 4.2.0)
108
- i18n (1.8.2)
109
+ i18n (1.8.3)
109
110
  concurrent-ruby (~> 1.0)
110
111
  ice_nine (0.11.2)
111
112
  listen (3.1.5)
112
113
  rb-fsevent (~> 0.9, >= 0.9.4)
113
114
  rb-inotify (~> 0.9, >= 0.9.7)
114
115
  ruby_dep (~> 1.2)
115
- loofah (2.4.0)
116
+ loofah (2.6.0)
116
117
  crass (~> 1.0.2)
117
118
  nokogiri (>= 1.5.9)
118
119
  mail (2.7.1)
119
120
  mini_mime (>= 0.1.1)
120
121
  marcel (0.3.3)
121
122
  mimemagic (~> 0.3.2)
122
- method_source (0.9.2)
123
- mimemagic (0.3.4)
123
+ method_source (1.0.0)
124
+ mimemagic (0.3.5)
124
125
  mini_mime (1.0.2)
125
126
  mini_portile2 (2.4.0)
126
- minitest (5.14.0)
127
+ minitest (5.14.1)
127
128
  msgpack (1.3.3)
128
129
  nio4r (2.5.2)
129
- nokogiri (1.10.9)
130
+ nokogiri (1.10.10)
130
131
  mini_portile2 (~> 2.4.0)
131
- pry (0.12.2)
132
- coderay (~> 1.1.0)
133
- method_source (~> 0.9.0)
134
- puma (4.3.3)
132
+ pry (0.13.1)
133
+ coderay (~> 1.1)
134
+ method_source (~> 1.0)
135
+ puma (4.3.5)
135
136
  nio4r (~> 2.0)
136
- rack (2.2.2)
137
+ rack (2.2.3)
137
138
  rack-test (1.1.0)
138
139
  rack (>= 1.0, < 3)
139
- rails (6.0.2.1)
140
- actioncable (= 6.0.2.1)
141
- actionmailbox (= 6.0.2.1)
142
- actionmailer (= 6.0.2.1)
143
- actionpack (= 6.0.2.1)
144
- actiontext (= 6.0.2.1)
145
- actionview (= 6.0.2.1)
146
- activejob (= 6.0.2.1)
147
- activemodel (= 6.0.2.1)
148
- activerecord (= 6.0.2.1)
149
- activestorage (= 6.0.2.1)
150
- activesupport (= 6.0.2.1)
140
+ rails (6.0.3.2)
141
+ actioncable (= 6.0.3.2)
142
+ actionmailbox (= 6.0.3.2)
143
+ actionmailer (= 6.0.3.2)
144
+ actionpack (= 6.0.3.2)
145
+ actiontext (= 6.0.3.2)
146
+ actionview (= 6.0.3.2)
147
+ activejob (= 6.0.3.2)
148
+ activemodel (= 6.0.3.2)
149
+ activerecord (= 6.0.3.2)
150
+ activestorage (= 6.0.3.2)
151
+ activesupport (= 6.0.3.2)
151
152
  bundler (>= 1.3.0)
152
- railties (= 6.0.2.1)
153
+ railties (= 6.0.3.2)
153
154
  sprockets-rails (>= 2.0.0)
154
155
  rails-dom-testing (2.0.3)
155
156
  activesupport (>= 4.2.0)
156
157
  nokogiri (>= 1.6)
157
158
  rails-html-sanitizer (1.3.0)
158
159
  loofah (~> 2.3)
159
- railties (6.0.2.1)
160
- actionpack (= 6.0.2.1)
161
- activesupport (= 6.0.2.1)
160
+ railties (6.0.3.2)
161
+ actionpack (= 6.0.3.2)
162
+ activesupport (= 6.0.3.2)
162
163
  method_source
163
164
  rake (>= 0.8.7)
164
165
  thor (>= 0.20.3, < 2.0)
165
166
  rake (13.0.1)
166
- rb-fsevent (0.10.3)
167
+ rb-fsevent (0.10.4)
167
168
  rb-inotify (0.10.1)
168
169
  ffi (~> 1.0)
170
+ rspec-core (3.9.2)
171
+ rspec-support (~> 3.9.3)
172
+ rspec-expectations (3.9.2)
173
+ diff-lcs (>= 1.2.0, < 2.0)
174
+ rspec-support (~> 3.9.0)
175
+ rspec-mocks (3.9.1)
176
+ diff-lcs (>= 1.2.0, < 2.0)
177
+ rspec-support (~> 3.9.0)
178
+ rspec-rails (4.0.1)
179
+ actionpack (>= 4.2)
180
+ activesupport (>= 4.2)
181
+ railties (>= 4.2)
182
+ rspec-core (~> 3.9)
183
+ rspec-expectations (~> 3.9)
184
+ rspec-mocks (~> 3.9)
185
+ rspec-support (~> 3.9)
186
+ rspec-support (3.9.3)
169
187
  ruby_dep (1.5.0)
170
188
  spring (2.1.0)
171
189
  spring-watcher-listen (2.0.1)
172
190
  listen (>= 2.7, < 4.0)
173
191
  spring (>= 1.2, < 3.0)
174
- sprockets (4.0.0)
192
+ sprockets (4.0.2)
175
193
  concurrent-ruby (~> 1.0)
176
194
  rack (> 1, < 3)
177
195
  sprockets-rails (3.2.1)
@@ -181,32 +199,31 @@ GEM
181
199
  sqlite3 (1.4.2)
182
200
  thor (1.0.1)
183
201
  thread_safe (0.3.6)
184
- tzinfo (1.2.6)
202
+ tzinfo (1.2.7)
185
203
  thread_safe (~> 0.1)
186
- websocket-driver (0.7.1)
204
+ websocket-driver (0.7.3)
187
205
  websocket-extensions (>= 0.1.0)
188
- websocket-extensions (0.1.4)
189
- zeitwerk (2.3.0)
206
+ websocket-extensions (0.1.5)
207
+ zeitwerk (2.4.0)
190
208
 
191
209
  PLATFORMS
192
210
  ruby
193
211
 
194
212
  DEPENDENCIES
213
+ actionpack (>= 6.0.3.2)
195
214
  bootsnap (>= 1.4.2)
196
215
  byebug
197
216
  dry-types-rails
198
217
  listen (>= 3.0.5, < 3.2)
199
218
  pry
200
- puma (~> 4.1)
201
- rails (~> 6.0.2, >= 6.0.2.1)
219
+ puma (~> 4.3)
220
+ rails (~> 6.0.2, >= 6.0.2.2)
221
+ rspec-rails
202
222
  sober_swag!
203
223
  spring
204
224
  spring-watcher-listen (~> 2.0.0)
205
225
  sqlite3 (~> 1.4)
206
226
  tzinfo-data
207
227
 
208
- RUBY VERSION
209
- ruby 2.7.0p0
210
-
211
228
  BUNDLED WITH
212
- 2.1.2
229
+ 2.1.4
@@ -1,68 +1,86 @@
1
+ ##
2
+ # Demonstration controller that involves people.
1
3
  class PeopleController < ApplicationController
2
-
3
4
  include SoberSwag::Controller
4
5
 
5
6
  before_action :load_person, only: %i[show update]
6
7
 
8
+ PersonBodyParams = SoberSwag.input_object do
9
+ identifier 'PersonBodyParams'
7
10
 
8
- PersonBodyParams = SoberSwag.struct do
9
11
  attribute :first_name, SoberSwag::Types::String
10
12
  attribute :last_name, SoberSwag::Types::String
11
13
  attribute? :date_of_birth, SoberSwag::Types::Params::DateTime.optional
12
14
  end
13
15
 
14
- PersonParams = SoberSwag.struct do
16
+ PersonBodyPatchParams = SoberSwag.input_object(PersonBodyParams) do
17
+ identifier 'PersonBodyPatchParams'
18
+
19
+ attribute? :first_name, SoberSwag::Types::String
20
+ attribute? :last_name, SoberSwag::Types::String
21
+ attribute? :date_of_birth, SoberSwag::Types::Params::DateTime.optional
22
+ end
23
+
24
+ PersonParams = SoberSwag.input_object do
25
+ identifier 'PersonParams'
15
26
  attribute :person, PersonBodyParams
16
27
  end
17
28
 
18
- PersonSerializer = SoberSwag::Blueprint.define do
19
- field :id, primitive(:Integer)
20
- field :first_name, primitive(:String)
21
- field :last_name, primitive(:String)
29
+ PersonPatchParams = SoberSwag.input_object do
30
+ identifier 'PersonPatchParams'
31
+ attribute :person, PersonBodyPatchParams
22
32
  end
23
33
 
24
34
  define :post, :create, '/people/' do
25
35
  request_body(PersonParams)
26
- response(:ok, 'the person created', PersonSerializer)
36
+ response(:ok, 'the person created', PersonOutputObject)
37
+ response(:unprocessable_entity, 'the validation errors', PersonErrorsOutputObject)
27
38
  end
28
39
  def create
29
- p = Person.create!(parsed_body.to_h)
30
- respond!(:ok, p)
40
+ p = Person.new(parsed_body.person.to_h)
41
+ if p.save
42
+ respond!(:ok, p)
43
+ else
44
+ respond!(:unprocessable_entity, p.errors)
45
+ end
31
46
  end
32
47
 
33
48
  define :patch, :update, '/people/{id}' do
34
- request_body(PersonParams)
49
+ request_body(PersonPatchParams)
35
50
  path_params { attribute :id, Types::Params::Integer }
36
- response(:ok, 'the person updated', PersonSerializer)
51
+ response(:ok, 'the person updated', PersonOutputObject)
52
+ response(:unprocessable_entity, 'the validation errors', PersonErrorsOutputObject)
37
53
  end
38
54
  def update
39
- if @person.update(parsed_body.to_h)
55
+ if @person.update(parsed_body.person.to_h)
40
56
  respond!(:ok, @person)
41
57
  else
42
- render json: @person.errors, status: :unprocessable_entity
58
+ respond!(:unprocessable_entity, @person.errors)
43
59
  end
44
60
  end
45
61
 
46
62
  define :get, :index, '/people/' do
47
63
  query_params do
48
- attribute? :first_name, Types::String
49
- attribute? :last_name, Types::String
64
+ attribute? :filters do
65
+ attribute? :first_name, Types::String
66
+ attribute? :last_name, Types::String
67
+ end
68
+ attribute :view, Types::String.default('base'.freeze).enum('base', 'detail')
50
69
  end
51
- response(:ok, 'all the people', PersonSerializer.new.array)
70
+ response(:ok, 'all the people', PersonOutputObject.array)
52
71
  end
53
-
54
72
  def index
55
73
  @people = Person.all
56
- @people = @people.where('first_name ILIKE ?', "%#{parsed_query.first_name}%") if parsed_query.first_name
57
- @people = @people.where('last_name ILIKE ?', "%#{parsed_query.last_name}%") if parsed_query.last_name
58
- respond!(:ok, @people)
59
- end
74
+ @people = @people.where('UPPER(first_name) LIKE UPPER(?)', "%#{parsed_query.filters.first_name}%") if parsed_query.filters&.first_name
75
+ @people = @people.where('UPPER(last_name) LIKE UPPER(?)', "%#{parsed_query.filters.last_name}%") if parsed_query.filters&.last_name
76
+ respond!(:ok, @people.includes(:posts), serializer_opts: { view: parsed_query.view })
77
+ end
60
78
 
61
79
  define :get, :show, '/people/{id}' do
62
80
  path_params do
63
81
  attribute :id, Types::Params::Integer
64
82
  end
65
- response(:ok, 'the person requested', PersonSerializer.new)
83
+ response(:ok, 'the person requested', PersonOutputObject)
66
84
  end
67
85
  def show
68
86
  respond!(:ok, @person)
@@ -0,0 +1,110 @@
1
+ ##
2
+ # Example controller for posts.
3
+ class PostsController < ApplicationController
4
+ before_action :set_post, only: %i[show update destroy]
5
+
6
+ include SoberSwag::Controller
7
+
8
+ PostCreateParamsBody = SoberSwag.input_object do
9
+ identifier 'PostCreateParamsBody'
10
+ attribute :person_id, SoberSwag::Types::Params::Integer.meta(description: 'Unique ID obtained from a person')
11
+ attribute :title, SoberSwag::Types::String.meta(description: 'Short title of a post')
12
+ attribute :body, SoberSwag::Types::String.meta(description: 'Post body in markdown format')
13
+ end
14
+
15
+ PostCreate = SoberSwag.input_object do
16
+ identifier 'PostCreate'
17
+ attribute :post, PostCreateParamsBody
18
+ end
19
+
20
+ PostUpdateParamsBody = SoberSwag.input_object do
21
+ identifier 'PostUpdateParamsBody'
22
+ attribute? :person_id, SoberSwag::Types::Params::Integer
23
+ attribute? :title, SoberSwag::Types::String
24
+ attribute? :body, SoberSwag::Types::String
25
+ end
26
+
27
+ PostUpdate = SoberSwag.input_object do
28
+ identifier 'PostUpdate'
29
+ attribute :post, PostUpdateParamsBody
30
+ end
31
+
32
+ ViewTypes = SoberSwag::Types::String.enum('base', 'detail')
33
+
34
+ ShowPath = SoberSwag.input_object do
35
+ identifier 'ShowPersonPathParams'
36
+ attribute :id, Types::Params::Integer
37
+ end
38
+
39
+ define :get, :index, '/posts/' do
40
+ query_params do
41
+ attribute? :view, ViewTypes
42
+ attribute :include_first, SoberSwag::Types::Params::Bool.default(false).meta(description: <<~MARKDOWN)
43
+ For historical reasons the first-ever post is the entire text of *Finnegan's Wake.*
44
+ Unfortunately, our contractors wound up depending on this quirk to complete dark arcane ceremonies,
45
+ so we can't remove it. Thus, by default, we don't include the first post unless you explicitly ask us to
46
+ (maybe you feel like some classic literature?).
47
+ MARKDOWN
48
+ end
49
+ response(:ok, 'all the posts', PostOutputObject.array)
50
+ end
51
+ def index
52
+ @posts = Post.all
53
+
54
+ @posts = @posts.where('id > 1') unless parsed_query.include_first
55
+
56
+ respond!(:ok, @posts.includes(:person), serializer_opts: { view: parsed_query.view })
57
+ end
58
+
59
+ define :get, :show, '/posts/{id}' do
60
+ path_params(ShowPath)
61
+ query_params { attribute? :view, ViewTypes }
62
+ response(:ok, 'the requested post', PostOutputObject)
63
+ end
64
+ def show
65
+ respond!(:ok, @post, serializer_opts: { view: parsed_query.view })
66
+ end
67
+
68
+ define :post, :create, '/posts/' do
69
+ request_body(PostCreate)
70
+ response(:created, 'the created post', PostOutputObject)
71
+ end
72
+ def create
73
+ @post = Post.new(parsed_body.post.to_h)
74
+
75
+ if @post.save
76
+ respond! :created, @post, rails_opts: { location: @post }
77
+ else
78
+ render json: @post.errors, status: :unprocessable_entity
79
+ end
80
+ end
81
+
82
+ define :patch, :update, '/posts/{id}' do
83
+ path_params(ShowPath)
84
+ request_body(PostUpdate)
85
+ response(:ok, 'the post updated', PostOutputObject.view(:base))
86
+ end
87
+ def update
88
+ if @post.update(parsed_body.post.to_h)
89
+ respond!(:ok, @post)
90
+ else
91
+ render json: @post.errors, status: :unprocessable_entity
92
+ end
93
+ end
94
+
95
+ define :delete, :destroy, '/posts/{id}' do
96
+ path_params(ShowPath)
97
+ response(:ok, 'the post deleted', PostOutputObject.view(:base))
98
+ end
99
+ def destroy
100
+ @post.destroy
101
+ respond!(:ok, @post)
102
+ end
103
+
104
+ private
105
+
106
+ # Use callbacks to share common setup or constraints between actions.
107
+ def set_post
108
+ @post = Post.find(parsed_path.id)
109
+ end
110
+ end