Skip to content

Commit 04d7efd

Browse files
author
Philip Champon
committed
updated documentation for entities
1 parent 1d88ac3 commit 04d7efd

File tree

2 files changed

+88
-5
lines changed

2 files changed

+88
-5
lines changed

README.markdown

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,11 +443,89 @@ RSpec.configure do |config|
443443
end
444444
```
445445

446+
## Reusable Responses with Entities
447+
448+
Entities are a simple and reusable means for converting Ruby objects to API responses.
449+
Entities can be used to conditionally include fields, nest other entities, and build
450+
ever larger responses, using inheritance.
451+
452+
### Defining Entities
453+
454+
Entities inherit from Grape::Entity, and define a simple DSL. The `#expose` method can be called in
455+
a number of ways. When processing options passed to exposures two keys will always be defined, :version
456+
and :collection. The :version key is define as api.version. The :collection key is boolean, and defined
457+
as true if the object presented is an array.
458+
459+
* expose SYMBOLS
460+
* define a list of fields which will always be exposed
461+
* expose SYMBOLS, HASH
462+
* HASH keys include :if, :unless, :proc, :as, :using, :format_with, :documentation
463+
* :if and :unless accept hashes (passed during runtime) or procs (arguments are object and options)
464+
* expose SYMBOL, {:format_with => :formatter}
465+
* expose a value, formatting it first
466+
* `:format_with` can only be applied to one exposure at a time
467+
* expose SYMBOL, {:as => "alias"}
468+
* Expose a value, changing its hash key from SYMBOL to alias
469+
* `:as` can only be applied to one exposure at a time
470+
* expose SYMBOL BLOCK
471+
* block arguments are object and options
472+
* expose the value returned by the block
473+
* `block` can only be applied to one exposure at a time
474+
475+
``` ruby
476+
module API
477+
module Entities
478+
class User < Grape::Entity
479+
expose :first_name, :last_name
480+
expose :field, :documentation => {:type => "string", :desc => "words go here"}
481+
expose :email, :if => {:type => :full}
482+
expose :user_type, user_id, :if => lambda{|user,options| user.confirmed?}
483+
expose(:name){|user,options| [user.first_name, user.last_name].join(' ')}
484+
expose :latest_status, :using => API::Status, :as => :status
485+
end
486+
end
487+
end
488+
489+
module API
490+
module Entities
491+
class UserDetailed < API::Entities::User
492+
expose :account_id
493+
end
494+
end
495+
end
496+
```
497+
498+
### Using Entities
499+
500+
Once an entity is defined, it can be used within endpoints, by calling #present. The #present
501+
method accepts two arguments, the object to be presented and the options associated with it. The
502+
options hash must always include :with, which defines the entity to expose.
503+
504+
If the entity includes documentation it can be included in an endpoint's description.
505+
506+
``` ruby
507+
module API
508+
class Users < Grape::API
509+
version 'v1'
510+
511+
desc 'User index', {
512+
:object_fields => API::Entities::User.documentation
513+
}
514+
get '/users' do
515+
@users = User.all
516+
type = current_user.admin? ? :full : :default
517+
present @users, with: API::Entities::User, :type => type
518+
end
519+
end
520+
end
521+
```
522+
446523
## Describing and Inspecting an API
447524

448525
Grape lets you add a description to an API along with any other optional
449526
elements that can also be inspected at runtime.
450-
This can be useful for generating documentation.
527+
This can be useful for generating documentation. If the response
528+
requires documentation, consider using an entity.
451529

452530
``` ruby
453531
class TwitterAPI < Grape::API

lib/grape/entity.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ class Entity
6363
# will be called with the represented object as well as the
6464
# runtime options that were passed in. You can also just supply a
6565
# block to the expose call to achieve the same effect.
66+
# @option options :documentation Provide documenation for an exposed
67+
# field, typically the value is a hash with two fields, type and desc.
68+
# Call the class or instance method #documentation for use with #desc.
69+
# When calling #docmentation, any exposure without a documentation key
70+
# will be ignored.
6671
def self.expose(*args, &block)
6772
options = args.last.is_a?(Hash) ? args.pop : {}
6873

@@ -71,7 +76,7 @@ def self.expose(*args, &block)
7176
raise ArgumentError, "You may not use block-setting on multi-attribute exposures." if block_given?
7277
end
7378

74-
raise ArgumentError, "You may not use block-setting when also using " if block_given? && options[:format_with].respond_to?(:call)
79+
raise ArgumentError, "You may not use block-setting when also using format_with" if block_given? && options[:format_with].respond_to?(:call)
7580

7681
options[:proc] = block if block_given?
7782

@@ -94,8 +99,8 @@ def self.exposures
9499
end
95100

96101
# Returns a hash of documentation hashes that have been declared for this Entity or ancestors. The keys
97-
# are symbolized references to methods on the containing object, the values are
98-
# the options that were passed into expose.
102+
# are symbolized references to fields in the response, the values are those defined in the
103+
# Entity's documentation key.
99104
def self.documentation
100105
@documentation ||= exposures.inject({}) do |memo, value|
101106
unless value[1][:documentation].nil? || value[1][:documentation].empty?
@@ -140,7 +145,7 @@ def self.documentation
140145
# end
141146
#
142147
def self.format_with(name, &block)
143-
raise ArgumentError, "You must has a block for formatters" unless block_given?
148+
raise ArgumentError, "You must pass a block for formatters" unless block_given?
144149
formatters[name.to_sym] = block
145150
end
146151

0 commit comments

Comments
 (0)