brainstem 1.0.0.pre.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +383 -32
- data/bin/brainstem +6 -0
- data/brainstem.gemspec +2 -0
- data/docs/api_doc_generator.markdown +175 -0
- data/docs/brainstem_executable.markdown +32 -0
- data/docs/docgen.png +0 -0
- data/docs/docgen_ascii.txt +63 -0
- data/docs/executable.png +0 -0
- data/docs/executable_ascii.txt +10 -0
- data/lib/brainstem/api_docs.rb +146 -0
- data/lib/brainstem/api_docs/abstract_collection.rb +116 -0
- data/lib/brainstem/api_docs/atlas.rb +158 -0
- data/lib/brainstem/api_docs/builder.rb +167 -0
- data/lib/brainstem/api_docs/controller.rb +122 -0
- data/lib/brainstem/api_docs/controller_collection.rb +40 -0
- data/lib/brainstem/api_docs/endpoint.rb +234 -0
- data/lib/brainstem/api_docs/endpoint_collection.rb +58 -0
- data/lib/brainstem/api_docs/exceptions.rb +8 -0
- data/lib/brainstem/api_docs/formatters/abstract_formatter.rb +64 -0
- data/lib/brainstem/api_docs/formatters/markdown/controller_formatter.rb +76 -0
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter.rb +73 -0
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +169 -0
- data/lib/brainstem/api_docs/formatters/markdown/helper.rb +76 -0
- data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +200 -0
- data/lib/brainstem/api_docs/introspectors/abstract_introspector.rb +100 -0
- data/lib/brainstem/api_docs/introspectors/rails_introspector.rb +232 -0
- data/lib/brainstem/api_docs/presenter.rb +225 -0
- data/lib/brainstem/api_docs/presenter_collection.rb +97 -0
- data/lib/brainstem/api_docs/resolver.rb +73 -0
- data/lib/brainstem/api_docs/sinks/abstract_sink.rb +37 -0
- data/lib/brainstem/api_docs/sinks/controller_presenter_multifile_sink.rb +93 -0
- data/lib/brainstem/api_docs/sinks/stdout_sink.rb +44 -0
- data/lib/brainstem/cli.rb +146 -0
- data/lib/brainstem/cli/abstract_command.rb +97 -0
- data/lib/brainstem/cli/generate_api_docs_command.rb +169 -0
- data/lib/brainstem/concerns/controller_dsl.rb +300 -0
- data/lib/brainstem/concerns/controller_param_management.rb +30 -9
- data/lib/brainstem/concerns/formattable.rb +38 -0
- data/lib/brainstem/concerns/inheritable_configuration.rb +3 -2
- data/lib/brainstem/concerns/optional.rb +43 -0
- data/lib/brainstem/concerns/presenter_dsl.rb +76 -15
- data/lib/brainstem/controller_methods.rb +6 -3
- data/lib/brainstem/dsl/association.rb +6 -3
- data/lib/brainstem/dsl/associations_block.rb +6 -3
- data/lib/brainstem/dsl/base_block.rb +2 -4
- data/lib/brainstem/dsl/conditional.rb +7 -3
- data/lib/brainstem/dsl/conditionals_block.rb +4 -4
- data/lib/brainstem/dsl/configuration.rb +184 -8
- data/lib/brainstem/dsl/field.rb +6 -3
- data/lib/brainstem/dsl/fields_block.rb +2 -3
- data/lib/brainstem/help_text.txt +8 -0
- data/lib/brainstem/presenter.rb +27 -6
- data/lib/brainstem/presenter_validator.rb +5 -2
- data/lib/brainstem/time_classes.rb +1 -1
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/api_docs/abstract_collection_spec.rb +156 -0
- data/spec/brainstem/api_docs/atlas_spec.rb +353 -0
- data/spec/brainstem/api_docs/builder_spec.rb +100 -0
- data/spec/brainstem/api_docs/controller_collection_spec.rb +92 -0
- data/spec/brainstem/api_docs/controller_spec.rb +225 -0
- data/spec/brainstem/api_docs/endpoint_collection_spec.rb +144 -0
- data/spec/brainstem/api_docs/endpoint_spec.rb +346 -0
- data/spec/brainstem/api_docs/formatters/abstract_formatter_spec.rb +30 -0
- data/spec/brainstem/api_docs/formatters/markdown/controller_formatter_spec.rb +126 -0
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter_spec.rb +85 -0
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +261 -0
- data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +100 -0
- data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +485 -0
- data/spec/brainstem/api_docs/introspectors/abstract_introspector_spec.rb +192 -0
- data/spec/brainstem/api_docs/introspectors/rails_introspector_spec.rb +170 -0
- data/spec/brainstem/api_docs/presenter_collection_spec.rb +84 -0
- data/spec/brainstem/api_docs/presenter_spec.rb +519 -0
- data/spec/brainstem/api_docs/resolver_spec.rb +72 -0
- data/spec/brainstem/api_docs/sinks/abstract_sink_spec.rb +16 -0
- data/spec/brainstem/api_docs/sinks/controller_presenter_multifile_sink_spec.rb +56 -0
- data/spec/brainstem/api_docs/sinks/stdout_sink_spec.rb +22 -0
- data/spec/brainstem/api_docs_spec.rb +58 -0
- data/spec/brainstem/cli/abstract_command_spec.rb +91 -0
- data/spec/brainstem/cli/generate_api_docs_command_spec.rb +125 -0
- data/spec/brainstem/cli_spec.rb +67 -0
- data/spec/brainstem/concerns/controller_dsl_spec.rb +471 -0
- data/spec/brainstem/concerns/controller_param_management_spec.rb +36 -16
- data/spec/brainstem/concerns/formattable_spec.rb +30 -0
- data/spec/brainstem/concerns/inheritable_configuration_spec.rb +104 -4
- data/spec/brainstem/concerns/optional_spec.rb +48 -0
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +202 -31
- data/spec/brainstem/dsl/association_spec.rb +18 -2
- data/spec/brainstem/dsl/conditional_spec.rb +25 -2
- data/spec/brainstem/dsl/configuration_spec.rb +1 -1
- data/spec/brainstem/dsl/field_spec.rb +18 -2
- data/spec/brainstem/presenter_collection_spec.rb +10 -2
- data/spec/brainstem/presenter_spec.rb +32 -0
- data/spec/brainstem/presenter_validator_spec.rb +12 -7
- data/spec/dummy/rails.rb +49 -0
- data/spec/shared/atlas_taker.rb +18 -0
- data/spec/shared/formattable.rb +14 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helpers/db.rb +1 -1
- data/spec/spec_helpers/presenters.rb +20 -14
- metadata +106 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 115ca6ee598304821711410e09788b194b4463d3
|
4
|
+
data.tar.gz: eb49966eafe33595f32048f087ee7148a0b4da36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45af28ac0b45a91167174b0809e79c22a20864cb2facb3c59c23fdad0d71e62dec0299db8f74748a0c0306169aa05eaf756f5564459f43d19edb2b0045bbb30c
|
7
|
+
data.tar.gz: 8050a810b6b1046d00d7aa961bebe48698604be562f28c73943c5160d4668b47c92ff9c4bb52a03e67eb67804d4f9d5a8391507cd5328b8138546e7febefcdc8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
+ **1.0.0 - _07/20/2017_
|
4
|
+
- Add the capability to generate the documentation extracted from your properly annotated
|
5
|
+
presenters and controllers using `bundle exec brainstem generate [ARGS]`.
|
6
|
+
- Update Brainstem to use Ruby version 2.3.3.
|
7
|
+
- Add support for Ruby versions 2.2.7, 2.3.4 & 2.4.1 and drop support for Ruby version 2.1.10.
|
8
|
+
- Drop support for specifying description param as a string and not with the `info` key in the options hash.
|
9
|
+
|
10
|
+
+ **1.0.0.pre.2** - _04/12/2017_
|
11
|
+
- Added support for specifying the description for conditionals, fields and associations with the `info` key in the options hash.
|
12
|
+
- Added a deprecation warning when description param is specified as a string and not with the `info` key in the options hash.
|
13
|
+
- Fixed: support for conditional, field and association options to be a hash with indifferent access.
|
14
|
+
|
3
15
|
+ **1.0.0.pre.1** - _03/07/2017_
|
4
16
|
- Implemented new presenter DSL.
|
5
17
|
- Added controller helpers for presenting errors.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -66,11 +66,11 @@ module Api
|
|
66
66
|
|
67
67
|
# Specify the fields to be present in the returned JSON.
|
68
68
|
fields do
|
69
|
-
field :name, :string, "the Widget's name"
|
70
|
-
field :legacy, :boolean, "true for legacy Widgets, false otherwise", via: :legacy?
|
71
|
-
field :longform_description, :string, "feature-length description of this Widget", optional: true
|
72
|
-
field :updated_at, :datetime, "the time of this Widget's last update"
|
73
|
-
field :created_at, :datetime, "the time at which this Widget was created"
|
69
|
+
field :name, :string, info: "the Widget's name"
|
70
|
+
field :legacy, :boolean, info: "true for legacy Widgets, false otherwise", via: :legacy?
|
71
|
+
field :longform_description, :string, info: "feature-length description of this Widget", optional: true
|
72
|
+
field :updated_at, :datetime, info: "the time of this Widget's last update"
|
73
|
+
field :created_at, :datetime, info: "the time at which this Widget was created"
|
74
74
|
end
|
75
75
|
|
76
76
|
# Associations can be included by providing include=association_name in the URL.
|
@@ -78,8 +78,8 @@ module Api
|
|
78
78
|
# columns on the model, otherwise the user must explicitly request associations
|
79
79
|
# to avoid unnecessary loads.
|
80
80
|
associations do
|
81
|
-
association :features, Feature, "features associated with this Widget"
|
82
|
-
association :location, Location, "the location of this Widget"
|
81
|
+
association :features, Feature, info: "features associated with this Widget"
|
82
|
+
association :location, Location, info: "the location of this Widget"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -119,6 +119,7 @@ The `Brainstem::ControllerMethods` concern provides:
|
|
119
119
|
* `brainstem_model_name` which is inferred from your controller name or settable with `self.brainstem_model_name = :thing`.
|
120
120
|
* `brainstem_present` and `brainstem_present_object` for presenting a scope of models or a single model.
|
121
121
|
* `brainstem_model_error` and `brainstem_system_error` for presenting model and system error messages.
|
122
|
+
* Various methods for auto-documentation of your API.
|
122
123
|
|
123
124
|
### Controller Best Practices
|
124
125
|
|
@@ -164,7 +165,7 @@ module Api
|
|
164
165
|
end
|
165
166
|
```
|
166
167
|
|
167
|
-
### Setup Rails to
|
168
|
+
### Setup Rails to Load Brainstem
|
168
169
|
|
169
170
|
To configure Brainstem for development and production, we do the following:
|
170
171
|
|
@@ -173,8 +174,9 @@ To configure Brainstem for development and production, we do the following:
|
|
173
174
|
2) We setup an initializer in `config/initializers/brainstem.rb`, similar to the following:
|
174
175
|
|
175
176
|
```ruby
|
176
|
-
# In order to support live code reload in the development environment, we
|
177
|
-
# runs once in production (before the
|
177
|
+
# In order to support live code reload in the development environment, we
|
178
|
+
# register a `to_prepare` callback. This # runs once in production (before the
|
179
|
+
# first request) and whenever a file has changed in development.
|
178
180
|
Rails.application.config.to_prepare do
|
179
181
|
# Forget all Brainstem configuration.
|
180
182
|
Brainstem.reset!
|
@@ -182,9 +184,11 @@ Rails.application.config.to_prepare do
|
|
182
184
|
# Set the current default API namespace.
|
183
185
|
Brainstem.default_namespace = :v1
|
184
186
|
|
185
|
-
# (Optional) Load a default base helper into all presenters. You could use
|
186
|
-
#
|
187
|
-
#
|
187
|
+
# (Optional) Load a default base helper into all presenters. You could use
|
188
|
+
# this to bring in a concept like `current_user`. # While not necessarily the
|
189
|
+
# best approach, something like http://stackoverflow.com/a/11670283 can
|
190
|
+
# currently be used to # access the requesting user inside of a Brainstem
|
191
|
+
# presenter. We hope to clean this up by allowing a user to be passed in #
|
188
192
|
# when presenting in the future.
|
189
193
|
module ApiHelper
|
190
194
|
def current_user
|
@@ -269,6 +273,343 @@ Brainstem parses the request params and supports the following:
|
|
269
273
|
keywords, such as `search`, `page`, `per_page`, `limit`, `offset`, `order`, `only`, or `include`.
|
270
274
|
* Brainstem supports optional fields which will only be returned when requested, for example: `optional_fields=field1,field2`
|
271
275
|
|
276
|
+
--
|
277
|
+
|
278
|
+
|
279
|
+
## The `brainstem` executable
|
280
|
+
|
281
|
+
The `brainstem` executable provided with the gem is at the moment used only to
|
282
|
+
generate API docs from the command line, but you can verify which commands are
|
283
|
+
available simply by running:
|
284
|
+
|
285
|
+
```sh
|
286
|
+
bundle exec brainstem
|
287
|
+
```
|
288
|
+
|
289
|
+
This will give you a list of all available commands. Additional help is
|
290
|
+
available for each command, and can be found by passing the command
|
291
|
+
the `help` flag, i.e.:
|
292
|
+
|
293
|
+
```sh
|
294
|
+
bundle exec brainstem generate --help
|
295
|
+
```
|
296
|
+
|
297
|
+
--
|
298
|
+
|
299
|
+
|
300
|
+
## API Documentation
|
301
|
+
|
302
|
+
### The `generate` command
|
303
|
+
|
304
|
+
Running `bundle exec brainstem generate [ARGS]` will generate the documentation
|
305
|
+
extracted from your properly annotated presenters and controllers.
|
306
|
+
|
307
|
+
Note that this does not, at present, *remove* existing docs that may be present
|
308
|
+
from a previous generation, so it is recommended that you use this executable as
|
309
|
+
part of a large shell script that empties your directory and regenerates over
|
310
|
+
top of it if you expect much churn.
|
311
|
+
|
312
|
+
### Customizing behavior
|
313
|
+
|
314
|
+
While options can be passed on the command line, this can complicate the
|
315
|
+
invocation, especially when the desired settings are often specific to the
|
316
|
+
project and do not often change.
|
317
|
+
|
318
|
+
As a result, it is possible to specify options through an initializer in your
|
319
|
+
application that will be used in the absence of command-line flags. Thus,
|
320
|
+
configuration precedence is in the following order:
|
321
|
+
|
322
|
+
1. Command-line flags;
|
323
|
+
2. Initializer settings;
|
324
|
+
3. Built-in defaults.
|
325
|
+
|
326
|
+
To see a list of the available command-line options, run `bundle exec brainstem
|
327
|
+
generate --help`.
|
328
|
+
|
329
|
+
To see a list of the available initializer settings, view
|
330
|
+
[lib/brainstem/api_docs.rb](./lib/brainstem/api_docs.rb). You can configure
|
331
|
+
these in your initializers just by setting them:
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
# config/initializers/brainstem.rb
|
335
|
+
|
336
|
+
Brainstem::ApiDocs.tap do |config|
|
337
|
+
config.write_path = "/path/to/output"
|
338
|
+
end
|
339
|
+
```
|
340
|
+
|
341
|
+
### Annotating an API
|
342
|
+
|
343
|
+
#### Presenters / Data Models
|
344
|
+
|
345
|
+
By and large, Presenters are self-documenting: simply using them as intended
|
346
|
+
will yield a panoply of data.
|
347
|
+
|
348
|
+
##### Docstrings
|
349
|
+
|
350
|
+
All common methods that do not explicitly take a description take an `:info`
|
351
|
+
option, which allows for the specification of an explanatory documentation
|
352
|
+
string.
|
353
|
+
|
354
|
+
As a general rule of thumb, methods that are not used within a block tend to
|
355
|
+
accept `:info` strings, and those used within a block tend to have their own
|
356
|
+
`description` argument.
|
357
|
+
|
358
|
+
For example:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
class MyPresenter < Brainstem::Presenter
|
362
|
+
sort_order :cost, info: "Sorts by cost" do |scope, direction|
|
363
|
+
scope.reorder("myobjects.cost #{direction}")
|
364
|
+
end
|
365
|
+
end
|
366
|
+
```
|
367
|
+
|
368
|
+
The methods that take an `:info` option include:
|
369
|
+
|
370
|
+
- `sort_order`
|
371
|
+
- `filter`
|
372
|
+
- `association`
|
373
|
+
- `request/model`
|
374
|
+
- `field` — also displays the documentation of any condition set in its
|
375
|
+
`:if` option.
|
376
|
+
|
377
|
+
The following do not accept documentation:
|
378
|
+
|
379
|
+
- `default_sort_order`
|
380
|
+
- `preload`
|
381
|
+
|
382
|
+
##### Nodoc
|
383
|
+
|
384
|
+
The following methods accept a `:nodoc` boolean option, which indicates that the
|
385
|
+
documentation should be suppressed for this particular entry:
|
386
|
+
|
387
|
+
- `association` — hides the association
|
388
|
+
- `field` — hides the field
|
389
|
+
- `sort_order` — hides the sort order
|
390
|
+
- `filter` — hides the filter
|
391
|
+
- `request` / `model` — causes the conditional not to be
|
392
|
+
listed on any field which specifies it
|
393
|
+
|
394
|
+
##### Additional Documentables
|
395
|
+
|
396
|
+
In addition to the above, there are three additional methods in the DSL designed
|
397
|
+
primarily for documentation:
|
398
|
+
|
399
|
+
- `nodoc!` — within a presenter or the `brainstem_params` block within a controller, skips generating the documentation entirely. Useful for hidden or non-public endpoints.
|
400
|
+
- `title(str, options)` — used to specify an alternate title for the
|
401
|
+
Presenter.
|
402
|
+
- `nodoc: true` — forces fallback to the Presenter's constant
|
403
|
+
- `description(str, options)` — used to specify a description for the
|
404
|
+
Presenter.
|
405
|
+
- `nodoc: true` — displays no description
|
406
|
+
|
407
|
+
##### Example
|
408
|
+
|
409
|
+
```ruby
|
410
|
+
class PostsPresenter < Brainstem::Presenter
|
411
|
+
presents Post
|
412
|
+
|
413
|
+
# Hide the entire presenter
|
414
|
+
#
|
415
|
+
# nodoc!
|
416
|
+
|
417
|
+
# If we temporarily want to disable the custom title, and just display
|
418
|
+
# 'Posts', we can add a 'nodoc' option set to true.
|
419
|
+
#
|
420
|
+
# title "Blog Posts", nodoc: true
|
421
|
+
|
422
|
+
title "Blog Posts"
|
423
|
+
|
424
|
+
description <<-MARKDOWN.strip_heredoc
|
425
|
+
The blog post is the primary entity in the blog, which represents a single
|
426
|
+
post by one of our authors.
|
427
|
+
MARKDOWN
|
428
|
+
|
429
|
+
associations do
|
430
|
+
association :author, User, info: "the author of the post"
|
431
|
+
|
432
|
+
# Temporarily disable documenting this relationship as we revamp the
|
433
|
+
# editorial system:
|
434
|
+
association :editor, User, info: "the editor of the post", nodoc: true
|
435
|
+
end
|
436
|
+
end
|
437
|
+
```
|
438
|
+
|
439
|
+
#### Controllers
|
440
|
+
|
441
|
+
The configuration for a controller takes place inside the `brainstem_params` block, e.g.:
|
442
|
+
|
443
|
+
```ruby
|
444
|
+
class PostsController < ApiController
|
445
|
+
include Brainstem::Concerns::ControllerDSL
|
446
|
+
|
447
|
+
brainstem_params do
|
448
|
+
title "Posts"
|
449
|
+
end
|
450
|
+
end
|
451
|
+
```
|
452
|
+
|
453
|
+
##### Action Contexts
|
454
|
+
|
455
|
+
Configuration that is specified within the root level of the `brainstem_params`
|
456
|
+
block is applied to the entire controller, and every action within the
|
457
|
+
controller. This is referred to as the 'default' context, because it is used as
|
458
|
+
the default for all actions. This lets you specify common defaults for all
|
459
|
+
actions, as well as a title and description for the controller, which, along
|
460
|
+
with an annotation of `nodoc!`, are not inherited by the actions.
|
461
|
+
|
462
|
+
Each action has its own action context, and the documentation is smart enough
|
463
|
+
to know that what you want to document for the `index` action is likely not
|
464
|
+
what you'd like to document for the `show` action, but you are also likely to
|
465
|
+
have your `create` and `update` methods be very similar.
|
466
|
+
|
467
|
+
You can define an action context and place any configuration inside this
|
468
|
+
context, and it will keep the documentation isolated to that specific action:
|
469
|
+
|
470
|
+
```ruby
|
471
|
+
brainstem_params do
|
472
|
+
valid :global_controller_param,
|
473
|
+
info: "A trivial example of a param that applies to all actions."
|
474
|
+
|
475
|
+
actions :index do
|
476
|
+
# This adds a `blog_id` param to just the `index` action.
|
477
|
+
valid :blog_id, info: "The id of the blog to which this post belongs"
|
478
|
+
end
|
479
|
+
|
480
|
+
actions :create, :update do
|
481
|
+
# This will add an `id` param to both `create` and `update` actions.
|
482
|
+
valid :id, info: "The id of the blog post"
|
483
|
+
end
|
484
|
+
end
|
485
|
+
```
|
486
|
+
|
487
|
+
Action contexts, like the default context, are inherited from the parent
|
488
|
+
controller. So it is often possible to express common setup in the more
|
489
|
+
abstract controllers, like so:
|
490
|
+
|
491
|
+
```ruby
|
492
|
+
class ApiController
|
493
|
+
brainstem_params do
|
494
|
+
actions :destroy do
|
495
|
+
presents nil
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
class PostsController << ApiController; end
|
501
|
+
```
|
502
|
+
|
503
|
+
In this example, `PostsController` will list no presenter for its `destroy`
|
504
|
+
method as it inherits this from `ApiController`.
|
505
|
+
|
506
|
+
**It is important to specify everything at the most specific level possible.**
|
507
|
+
Action contexts have a higher priority than defaults, and will fall back to the
|
508
|
+
action context of the parent controller before they check the default of the
|
509
|
+
child controller. It's therefore recommended that your documentation be kept
|
510
|
+
in action contexts as much as possible.
|
511
|
+
|
512
|
+
##### `title` / `description` / `nodoc!`
|
513
|
+
|
514
|
+
Any of these can be used inside an action context as well.
|
515
|
+
|
516
|
+
```ruby
|
517
|
+
class BlogPostsController < ApiController
|
518
|
+
brainstem_params do
|
519
|
+
|
520
|
+
# Make the displayed title of this controller "Posts"
|
521
|
+
title "Posts"
|
522
|
+
|
523
|
+
# Fall back to 'BlogPostsController' for a title
|
524
|
+
title "Posts", nodoc: true
|
525
|
+
|
526
|
+
# Show description
|
527
|
+
description "Access blog posts through these endpoints."
|
528
|
+
|
529
|
+
# Hide description
|
530
|
+
description "...", nodoc: true
|
531
|
+
|
532
|
+
# Do not document this controller or any of its endpoints!
|
533
|
+
nodoc!
|
534
|
+
|
535
|
+
actions :index do
|
536
|
+
# Set the title of this action
|
537
|
+
title "Listing blog posts"
|
538
|
+
description "..."
|
539
|
+
end
|
540
|
+
|
541
|
+
actions :show do
|
542
|
+
# Do not display this action.
|
543
|
+
nodoc!
|
544
|
+
end
|
545
|
+
|
546
|
+
end
|
547
|
+
end
|
548
|
+
```
|
549
|
+
|
550
|
+
|
551
|
+
##### `valid` / `model_params`
|
552
|
+
|
553
|
+
```ruby
|
554
|
+
class BlogPostsController < ApiController
|
555
|
+
brainstem_params do
|
556
|
+
|
557
|
+
# Add an `:category_id` param to all actions in this controller / children:
|
558
|
+
valid :category_id, info: "(required) the category's ID"
|
559
|
+
|
560
|
+
# Do not document this additional field.
|
561
|
+
valid :lang,
|
562
|
+
info: "(optional) the language of the requested post",
|
563
|
+
nodoc: true
|
564
|
+
|
565
|
+
actions :show do
|
566
|
+
# Declare a nested param under the `brainstem_model_name` root key,
|
567
|
+
# i.e. `params[:blog_post][:id]`):
|
568
|
+
model_params do |post|
|
569
|
+
post.valid :id, info: "(required) the id of the post"
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
actions :share do
|
574
|
+
# Declare a nested param with an explicit root key:, i.e. `params[:share][...]`
|
575
|
+
model_param :share do
|
576
|
+
# ...
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
|
581
|
+
def self.param_root
|
582
|
+
:widgets
|
583
|
+
end
|
584
|
+
|
585
|
+
|
586
|
+
actions :update do
|
587
|
+
# Declare a dynamic root key, i.e. `params[:widgets][:id]`
|
588
|
+
model_params(-> (controller_klass) { controller_class.param_root } do |p|
|
589
|
+
p.valid :id #, ...
|
590
|
+
end
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
```
|
595
|
+
|
596
|
+
##### `presents`
|
597
|
+
|
598
|
+
```ruby
|
599
|
+
class BlogPostsController < ApiController
|
600
|
+
brainstem_params do
|
601
|
+
# Includes a link to the presenter for `BlogPost` in each action.
|
602
|
+
presents BlogPost
|
603
|
+
end
|
604
|
+
```
|
605
|
+
|
606
|
+
### Extending and Customizing the API Documentation
|
607
|
+
|
608
|
+
For more information on extending and customizing the API documentation, please
|
609
|
+
see the
|
610
|
+
[API Doc Generator developer documentation](./docs/api_doc_generator.markdown).
|
611
|
+
|
612
|
+
|
272
613
|
--
|
273
614
|
|
274
615
|
For more detailed examples, please see the rest of this README and our detailed
|
@@ -524,12 +865,15 @@ Brainstem provides a rich DSL for building presenters. This section details the
|
|
524
865
|
|
525
866
|
```ruby
|
526
867
|
fields do
|
527
|
-
field :name, :string, "the Widget's name"
|
528
|
-
field :legacy, :boolean,
|
868
|
+
field :name, :string, info: "the Widget's name"
|
869
|
+
field :legacy, :boolean,
|
870
|
+
info: "true for legacy Widgets, false otherwise",
|
529
871
|
via: :legacy?
|
530
|
-
field :dynamic_name, :string,
|
872
|
+
field :dynamic_name, :string,
|
873
|
+
info: "a formatted name for this Widget",
|
531
874
|
dynamic: lambda { |widget| "This Widget's name is #{widget.name}" }
|
532
|
-
field :longform_description, :string,
|
875
|
+
field :longform_description, :string,
|
876
|
+
info: "feature-length description of this Widget",
|
533
877
|
optional: true
|
534
878
|
|
535
879
|
# Fields can be nested
|
@@ -561,14 +905,16 @@ Brainstem provides a rich DSL for building presenters. This section details the
|
|
561
905
|
|
562
906
|
```ruby
|
563
907
|
associations do
|
564
|
-
association :features, Feature, "features associated with this Widget"
|
565
|
-
association :location, Location, "the location of this Widget"
|
566
|
-
association :previous_location, Location,
|
908
|
+
association :features, Feature, info: "features associated with this Widget"
|
909
|
+
association :location, Location, info: "the location of this Widget"
|
910
|
+
association :previous_location, Location,
|
911
|
+
info: "the Widget's previous location",
|
567
912
|
dynamic: lambda { |widget| widget.previous_locations.first }
|
568
|
-
association :associated_objects, :polymorphic,
|
913
|
+
association :associated_objects, :polymorphic,
|
914
|
+
info: "a mixture of objects related to this Widget"
|
569
915
|
end
|
570
916
|
```
|
571
|
-
|
917
|
+
|
572
918
|
* `lookup` - Use this option to avoid N + 1 queries for Fields and Associations. The `lookup` lambda runs once when
|
573
919
|
presenting and every presented model gets its assocation or value from the cache the `lookup` lambda generates. The
|
574
920
|
`lookup` lambda takes in the presented models and should generate a cache containing the models' coresponding assocations
|
@@ -579,7 +925,8 @@ the `lookup` will be used.
|
|
579
925
|
|
580
926
|
```ruby
|
581
927
|
associations do
|
582
|
-
association :current_user_groups, Group,
|
928
|
+
association :current_user_groups, Group,
|
929
|
+
info: "the Groups for the current user",
|
583
930
|
lookup: lambda { |models|
|
584
931
|
Group.where(subject_id: models.map(&:id)
|
585
932
|
.where(user_id: current_user.id)
|
@@ -595,12 +942,13 @@ the `lookup` will be used.
|
|
595
942
|
|
596
943
|
```ruby
|
597
944
|
fields do
|
598
|
-
field :current_user_post_count, Post,
|
599
|
-
|
945
|
+
field :current_user_post_count, Post,
|
946
|
+
info: "count of Posts the current_user has for this model",
|
947
|
+
lookup: lambda { |models|
|
600
948
|
lookup = Post.where(subject_id: models.map(&:id)
|
601
949
|
.where(user_id: current_user.id)
|
602
|
-
.group_by { |post| post.subject_id }
|
603
|
-
|
950
|
+
.group_by { |post| post.subject_id }
|
951
|
+
|
604
952
|
lookup
|
605
953
|
},
|
606
954
|
lookup_fetch: lambda { |lookup, model| lookup[model.id] }
|
@@ -617,24 +965,27 @@ the `lookup` will be used.
|
|
617
965
|
conditionals do
|
618
966
|
model :title_is_hello,
|
619
967
|
lambda { |model| model.title == 'hello' },
|
620
|
-
'visible when the title is hello'
|
968
|
+
info: 'visible when the title is hello'
|
621
969
|
|
622
970
|
request :user_is_bob,
|
623
971
|
lambda { current_user == 'bob' }, # Assuming some sort of `helper` that provides `current_user`
|
624
|
-
'visible only to bob'
|
972
|
+
info: 'visible only to bob'
|
625
973
|
end
|
626
974
|
|
627
975
|
fields do
|
628
|
-
field :hello_title, :string,
|
976
|
+
field :hello_title, :string,
|
977
|
+
info: 'the title, when it is exactly the word "hello"',
|
629
978
|
dynamic: lambda { |model| model.title + " is the title" },
|
630
979
|
if: :title_is_hello
|
631
980
|
|
632
|
-
field :secret, :string,
|
981
|
+
field :secret, :string,
|
982
|
+
info: "a secret, via the secret_info model method, only visible to bob and when the model's title is hello",
|
633
983
|
via: :secret_info,
|
634
984
|
if: [:user_is_bob, :title_is_hello]
|
635
985
|
|
636
986
|
with_options if: :user_is_bob do
|
637
|
-
field :bob_title, :string,
|
987
|
+
field :bob_title, :string,
|
988
|
+
info: 'another name for the title, only visible to Bob',
|
638
989
|
via: :title
|
639
990
|
end
|
640
991
|
end
|