@@ -77,9 +77,18 @@ class Twitter::API < Grape::API
7777end
7878```
7979
80+ Optionally, you can define requirements for your named route parameters using regular expressions. The route will match only if
81+ all requirements are met.
82+
83+ ``` ruby
84+ get ' /show/:id' , :requirements => { :id => /[0-9] */ } do
85+ Tweet .find(params[:id ])
86+ end
87+ ```
88+
8089## Mounting
8190
82- The above sample creates a Rack application that can be run from a rackup * config.ru* file
91+ The above sample creates a Rack application that can be run from a rackup * config.ru* file
8392with ` rackup ` :
8493
8594``` ruby
@@ -119,7 +128,7 @@ There are three strategies in which clients can reach your API's endpoints: `:he
119128version ' v1' , :using => :header
120129```
121130
122- Using this versioning strategy, clients should pass the desired version in the HTTP Accept head.
131+ Using this versioning strategy, clients should pass the desired version in the HTTP Accept head.
123132
124133 curl -H Accept=application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
125134
@@ -138,15 +147,15 @@ Using this versioning strategy, clients should pass the desired version in the U
138147
139148 curl -H http://localhost:9292/v1/statuses/public_timeline
140149
141- Serialization takes place automatically.
150+ Serialization takes place automatically.
142151
143152### Param
144153
145154``` ruby
146155version ' v1' , :using => :param
147156```
148157
149- Using this versioning strategy, clients should pass the desired version as a request parameter, either in the URL query string or in the request body.
158+ Using this versioning strategy, clients should pass the desired version as a request parameter, either in the URL query string or in the request body.
150159
151160 curl -H http://localhost:9292/events?apiver=v1
152161
@@ -160,7 +169,7 @@ version 'v1', :using => :param, :parameter => "v"
160169
161170## Parameters
162171
163- Parameters are available through the ` params ` hash object. This includes ` GET ` and ` POST ` parameters,
172+ Parameters are available through the ` params ` hash object. This includes ` GET ` and ` POST ` parameters,
164173along with any named parameters you specify in your route strings.
165174
166175``` ruby
@@ -345,6 +354,51 @@ class Twitter::API < Grape::API
345354end
346355```
347356
357+ ## Logging
358+
359+ ` Grape::API ` provides a ` logger ` method which by default will return an instance of the ` Logger `
360+ class from Ruby's standard library.
361+
362+ To log messages from within an endpoint, you need to define a helper to make the logger
363+ available in the endpoint context:
364+
365+ ``` ruby
366+ class API < Grape ::API
367+ helpers do
368+ def logger
369+ API .logger
370+ end
371+ end
372+ get ' /hello' do
373+ logger.info " someone said hello"
374+ " hey there"
375+ end
376+ end
377+ ```
378+
379+ You can also set your own logger:
380+
381+ ``` ruby
382+ class MyLogger
383+ def warning (message )
384+ puts " this is a warning: #{ message } "
385+ end
386+ end
387+
388+ class API < Grape ::API
389+ logger MyLogger .new
390+ helpers do
391+ def logger
392+ API .logger
393+ end
394+ end
395+ get ' /hello' do
396+ logger.warning " someone said hello"
397+ " hey there"
398+ end
399+ end
400+ ```
401+
348402## Content-Types
349403
350404By default, Grape supports _ XML_ , _ JSON_ , _ Atom_ , _ RSS_ , and _ text_ content-types.
@@ -372,9 +426,20 @@ class Twitter::API < Grape::API
372426end
373427```
374428
429+ You can override the content-type by setting the ` Content-Type ` header.
430+
431+ ``` ruby
432+ class API < Grape ::API
433+ get ' /script' do
434+ content_type " application/javascript"
435+ " var x = 1;"
436+ end
437+ end
438+ ```
439+
375440## Writing Tests
376441
377- You can test a Grape API with RSpec by making HTTP requests and examining the response.
442+ You can test a Grape API with RSpec by making HTTP requests and examining the response.
378443
379444### Writing Tests with Rack
380445
@@ -443,11 +508,122 @@ RSpec.configure do |config|
443508end
444509```
445510
511+ ## Reusable Responses with Entities
512+
513+ Entities are a reusable means for converting Ruby objects to API responses.
514+ Entities can be used to conditionally include fields, nest other entities, and build
515+ ever larger responses, using inheritance.
516+
517+ ### Defining Entities
518+
519+ Entities inherit from Grape::Entity, and define a simple DSL. Exposures can use
520+ runtime options to determine which fields should be visible, these options are
521+ available to : if , : unless , and : proc . The option keys : version and : collection
522+ will always be defined. The : version key is defined as api.version. The
523+ : collection key is boolean, and defined as true if the object presented is an
524+ array.
525+
526+ * ` expose SYMBOLS `
527+ * define a list of fields which will always be exposed
528+ * ` expose SYMBOLS, HASH `
529+ * HASH keys include : if , : unless , : proc , : as , : using , : format_with , : documentation
530+ * : if and : unless accept hashes (passed during runtime) or procs (arguments are object and options)
531+ * ` expose SYMBOL, {:format_with => :formatter} `
532+ * expose a value, formatting it first
533+ * : format_with can only be applied to one exposure at a time
534+ * ` expose SYMBOL, {:as => "alias"} `
535+ * Expose a value, changing its hash key from SYMBOL to alias
536+ * : as can only be applied to one exposure at a time
537+ * ` expose SYMBOL BLOCK `
538+ * block arguments are object and options
539+ * expose the value returned by the block
540+ * block can only be applied to one exposure at a time
541+
542+ ``` ruby
543+ module API
544+ module Entities
545+ class User < Grape ::Entity
546+ expose :first_name , :last_name
547+ expose :field , :documentation => {:type => " string" , :desc => " words go here" }
548+ expose :email , :if => {:type => :full }
549+ expose :user_type , user_id, :if => lambda {|user ,options | user.confirmed?}
550+ expose(:name ){|user ,options | [user.first_name, user.last_name].join(' ' )}
551+ expose :latest_status , :using => API ::Status , :as => :status
552+ end
553+ end
554+ end
555+
556+ module API
557+ module Entities
558+ class UserDetailed < API ::Entities ::User
559+ expose :account_id
560+ end
561+ end
562+ end
563+ ```
564+
565+ ### Using Entities
566+
567+ Once an entity is defined, it can be used within endpoints, by calling #present. The #present
568+ method accepts two arguments, the object to be presented and the options associated with it. The
569+ options hash must always include : with , which defines the entity to expose.
570+
571+ If the entity includes documentation it can be included in an endpoint's description.
572+
573+ ``` ruby
574+ module API
575+ class Users < Grape ::API
576+ version ' v1'
577+
578+ desc ' User index' , {
579+ :object_fields => API ::Entities ::User .documentation
580+ }
581+ get ' /users' do
582+ @users = User .all
583+ type = current_user.admin? ? :full : :default
584+ present @users , with: API ::Entities ::User , :type => type
585+ end
586+ end
587+ end
588+ ```
589+
590+ ### Caveats
591+
592+ Entities with duplicate exposure names and conditions will silently overwrite one another.
593+ In the following example, when object#check equals "foo", only afield will be exposed.
594+ However, when object#check equals "bar" both bfield and foo will be exposed.
595+
596+ ``` ruby
597+ module API
598+ module Entities
599+ class User < Grape ::Entity
600+ expose :afield , :foo , :if => lambda {|object ,options | object.check== " foo" }
601+ expose :bfield , :foo , :if => lambda {|object ,options | object.check== " bar" }
602+ end
603+ end
604+ end
605+ ```
606+
607+ This can be problematic, when you have mixed collections. Using #respond_to? is safer.
608+
609+ ``` ruby
610+ module API
611+ module Entities
612+ class User < Grape ::Entity
613+ expose :afield , :if => lambda {|object ,options | object.check== " foo" }
614+ expose :bfield , :if => lambda {|object ,options | object.check== " bar" }
615+ expose :foo , :if => lambda {object,options| object.respond_to?(:foo )}
616+ end
617+ end
618+ end
619+ ```
620+
446621## Describing and Inspecting an API
447622
448623Grape lets you add a description to an API along with any other optional
449624elements that can also be inspected at runtime.
450- This can be useful for generating documentation.
625+ This can be useful for generating documentation. If the response
626+ requires documentation, consider using an entity.
451627
452628``` ruby
453629class TwitterAPI < Grape ::API
@@ -485,13 +661,13 @@ Parameters can also be tagged to the method declaration itself.
485661
486662``` ruby
487663class StringAPI < Grape ::API
488- get " split/:string" , { :params => [ " token" ] , :optional_params => [ " limit" ] } do
664+ get " split/:string" , { :params => { " token" => " a token " } , :optional_params => { " limit" => " the limit " } } do
489665 params[:string ].split(params[:token ], (params[:limit ] || 0 ))
490666 end
491667end
492668
493- StringAPI ::routes[0 ].route_params # yields an array [ "string", "token" ]
494- StringAPI ::routes[0 ].route_optional_params # yields an array [ "limit" ]
669+ StringAPI ::routes[0 ].route_params # yields a hash { "string" => "" , "token" => "a token"}
670+ StringAPI ::routes[0 ].route_optional_params # yields a hash { "limit" => "the limit"}
495671```
496672
497673It's possible to retrieve the information about the current route from within an API call with ` route ` .
@@ -505,6 +681,33 @@ class MyAPI < Grape::API
505681end
506682```
507683
684+ You can use this information to create a helper that will check if the request has
685+ all required parameters:
686+
687+ ``` ruby
688+ class MyAPI < Grape ::API
689+
690+ helpers do
691+ def validate_request!
692+ # skip validation if no parameter is declared
693+ return unless route.route_params
694+ route.route_params.each do |k , v |
695+ if ! params.has_key? k
696+ error!(" Missing field: #{ k } " , 400 )
697+ end
698+ end
699+ end
700+ end
701+
702+ before { validate_request! }
703+
704+ desc " creates a new item resource" , :params => { :name => ' name is a required parameter' }
705+ post :items do
706+ ...
707+ end
708+ end
709+ ```
710+
508711## Anchoring
509712
510713Grape by default anchors all request paths, which means that the request URL
0 commit comments