Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 720 lines (554 sloc) 18.228 kb
b894c4c @mbleigh Bumps version to v0.2.0
mbleigh authored
1 # Grape [![Build Status](http://travis-ci.org/intridea/grape.png?branch=frontier)](http://travis-ci.org/intridea/grape)
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
2
5e16531 @dblock Added the project tracking section.
dblock authored
3 ## What is Grape?
4
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
5 Grape is a REST-like API micro-framework for Ruby. It is built to complement
6 existing web application frameworks such as Rails and Sinatra by providing a
7 simple DSL to easily provide APIs. It has built-in support for common
8 conventions such as multiple formats, subdomain/prefix restriction, and
9 versioning.
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
10
5e16531 @dblock Added the project tracking section.
dblock authored
11 ## Project Tracking
12
13 * [Grape Google Group](http://groups.google.com/group/ruby-grape)
14 * [Grape Wiki](https://github.com/intridea/grape/wiki)
15
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
16 ## Installation
17
18 Grape is available as a gem, to install it just install the gem:
19
20 gem install grape
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
21
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
22 If you're using Bundler, add the gem to Gemfile.
23
24 gem 'grape'
25
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
26 ## Basic Usage
27
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
28 Grape APIs are Rack applications that are created by subclassing `Grape::API`.
29 Below is a simple example showing some of the more common features of Grape in
30 the context of recreating parts of the Twitter API.
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
31
e61c905 @dblock Fixed typo.
dblock authored
32 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
33 class Twitter::API < Grape::API
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
34 version 'v1', :using => :header, :vendor => 'twitter'
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
35
36 helpers do
37 def current_user
38 @current_user ||= User.authorize!(env)
39 end
40
41 def authenticate!
42 error!('401 Unauthorized', 401) unless current_user
43 end
44 end
45
46 resource :statuses do
47 get :public_timeline do
48 Tweet.limit(20)
49 end
50
51 get :home_timeline do
52 authenticate!
53 current_user.home_timeline
54 end
55
56 get '/show/:id' do
57 Tweet.find(params[:id])
58 end
59
60 post :update do
61 authenticate!
62 Tweet.create(
63 :user => current_user,
64 :text => params[:status]
65 )
66 end
67 end
68
69 resource :account do
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
70 before { authenticate! }
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
71
72 get '/private' do
73 "Congratulations, you found the secret!"
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
74 end
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
75 end
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
76
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
77 end
78 ```
79
b5bf0ae @ppadron adding docs for named route parameters requirements
ppadron authored
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
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
89 ## Mounting
90
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
91 The above sample creates a Rack application that can be run from a rackup *config.ru* file
92 with `rackup`:
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
93
e61c905 @dblock Fixed typo.
dblock authored
94 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
95 run Twitter::API
96 ```
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
97
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
98 And would respond to the following routes:
99
a99ad72 @jch update README: default versioning strategy uses
jch authored
100 GET /statuses/public_timeline(.json)
101 GET /statuses/home_timeline(.json)
102 GET /statuses/show/:id(.json)
103 POST /statuses/update(.json)
104
948917e @dblock Spellcheck.
dblock authored
105 In a Rails application, modify *config/routes*:
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
106
e61c905 @dblock Fixed typo.
dblock authored
107 ``` ruby
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
108 mount Twitter::API => "/"
109 ```
110
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
111 You can mount multiple API implementations inside another one.
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
112
113 ```ruby
114 class Twitter::API < Grape::API
115 mount Twitter::APIv1
116 mount Twitter::APIv2
117 end
118 ```
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
119
120 ## Versioning
121
0d7f0f2 @jackcasey Grape::API versioning based on request parameter.
jackcasey authored
122 There are three strategies in which clients can reach your API's endpoints: `:header`, `:path` and `:param`. The default strategy is `:header`.
123
124
125 ### Header
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
126
089b2ce @dblock Markdown edits in README.
dblock authored
127 ```ruby
128 version 'v1', :using => :header
129 ```
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
130
131 Using this versioning strategy, clients should pass the desired version in the HTTP Accept head.
a99ad72 @jch update README: default versioning strategy uses
jch authored
132
133 curl -H Accept=application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
134
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
135 By default, the first matching version is used when no Accept header is
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
136 supplied. This behavior is similar to routing in Rails. To circumvent this default behavior,
137 one could use the `:strict` option. When this option is set to `true`, a `404 Not found` error
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
138 is returned when no correct Accept header is supplied.
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
139
0d7f0f2 @jackcasey Grape::API versioning based on request parameter.
jackcasey authored
140 ### Path
141
089b2ce @dblock Markdown edits in README.
dblock authored
142 ``` ruby
143 version 'v1', :using => :path
144 ```
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
145
146 Using this versioning strategy, clients should pass the desired version in the URL.
147
148 curl -H http://localhost:9292/v1/statuses/public_timeline
149
150 Serialization takes place automatically.
151
0d7f0f2 @jackcasey Grape::API versioning based on request parameter.
jackcasey authored
152 ### Param
153
089b2ce @dblock Markdown edits in README.
dblock authored
154 ```ruby
155 version 'v1', :using => :param
156 ```
0d7f0f2 @jackcasey Grape::API versioning based on request parameter.
jackcasey authored
157
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.
159
160 curl -H http://localhost:9292/events?apiver=v1
161
162 The default name for the query parameter is 'apiver' but can be specified using the :parameter option.
163
089b2ce @dblock Markdown edits in README.
dblock authored
164 ```ruby
165 version 'v1', :using => :param, :parameter => "v"
166 ```
0d7f0f2 @jackcasey Grape::API versioning based on request parameter.
jackcasey authored
167
089b2ce @dblock Markdown edits in README.
dblock authored
168 curl -H http://localhost:9292/events?v=v1
0d7f0f2 @jackcasey Grape::API versioning based on request parameter.
jackcasey authored
169
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
170 ## Parameters
171
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
172 Parameters are available through the `params` hash object. This includes `GET` and `POST` parameters,
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
173 along with any named parameters you specify in your route strings.
174
175 ```ruby
089b2ce @dblock Markdown edits in README.
dblock authored
176 get do
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
177 Article.order(params[:sort_by])
089b2ce @dblock Markdown edits in README.
dblock authored
178 end
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
179 ```
180
3be0f54 Add parameters documentation for request bodies.
Robert Ross authored
181 Parameters are also populated from the request body on POST and PUT for JSON and XML content-types.
182
183 The Request:
184
089b2ce @dblock Markdown edits in README.
dblock authored
185 ```curl -d '{"some_key": "some_value"}' 'http://localhost:9292/json_endpoint' -H Content-Type:application/json -v```
3be0f54 Add parameters documentation for request bodies.
Robert Ross authored
186
187 The Grape Endpoint:
089b2ce @dblock Markdown edits in README.
dblock authored
188
3be0f54 Add parameters documentation for request bodies.
Robert Ross authored
189 ```ruby
089b2ce @dblock Markdown edits in README.
dblock authored
190 post '/json_endpoint' do
3be0f54 Add parameters documentation for request bodies.
Robert Ross authored
191 params[:some_key]
089b2ce @dblock Markdown edits in README.
dblock authored
192 end
3be0f54 Add parameters documentation for request bodies.
Robert Ross authored
193 ```
194
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
195 ## Headers
196
197 Headers are available through the `env` hash object.
198
199 ```ruby
089b2ce @dblock Markdown edits in README.
dblock authored
200 get do
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
201 error! 'Unauthorized', 401 unless env['HTTP_SECRET_PASSWORD'] == 'swordfish'
202 ...
089b2ce @dblock Markdown edits in README.
dblock authored
203 end
83461a1 @dblock Updated docs with parameters, headers, versioning and mounting.
dblock authored
204 ```
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
205
e536bde @jch add helpers to README
jch authored
206 ## Helpers
207
208 You can define helper methods that your endpoints can use with the `helpers`
209 macro by either giving a block or a module:
210
e61c905 @dblock Fixed typo.
dblock authored
211 ``` ruby
e536bde @jch add helpers to README
jch authored
212 module MyHelpers
213 def say_hello(user)
214 "hey there #{user.name}"
215 end
216 end
217
218 class API < Grape::API
219 # define helpers with a block
220 helpers do
221 def current_user
222 User.find(params[:user_id])
223 end
224 end
225
226 # or mix in a module
227 helpers MyHelpers
228
229 get '/hello' do
230 # helpers available in your endpoint and filters
231 say_hello(current_user)
232 end
233 end
e61c905 @dblock Fixed typo.
dblock authored
234 ```
e536bde @jch add helpers to README
jch authored
235
49de4c3 @lukaszsliwa Added cookies examples to README
lukaszsliwa authored
236 ## Cookies
237
238 You can set, get and delete your cookies very simply using `cookies` method:
239
e61c905 @dblock Fixed typo.
dblock authored
240 ``` ruby
49de4c3 @lukaszsliwa Added cookies examples to README
lukaszsliwa authored
241 class API < Grape::API
242 get '/counter' do
243 cookies[:counter] ||= 0
244 cookies[:counter] += 1
245 { :counter => cookies[:counter] }
246 end
247
248 delete '/counter' do
249 { :result => cookies.delete(:counter) }
250 end
251 end
e61c905 @dblock Fixed typo.
dblock authored
252 ```
49de4c3 @lukaszsliwa Added cookies examples to README
lukaszsliwa authored
253
d2cb2dc @lukaszsliwa One word README update
lukaszsliwa authored
254 To set more than value use hash-based syntax:
49de4c3 @lukaszsliwa Added cookies examples to README
lukaszsliwa authored
255
e61c905 @dblock Fixed typo.
dblock authored
256 ``` ruby
49de4c3 @lukaszsliwa Added cookies examples to README
lukaszsliwa authored
257 cookies[:counter] = {
258 :value => 0,
259 :expires => Time.tomorrow,
260 :domain => '.example.com',
261 :path => '/'
262 }
263 cookies[:counter][:value] +=1
e61c905 @dblock Fixed typo.
dblock authored
264 ```
7e49d27 @allenwei support permanent redirect, add document in readme
allenwei authored
265 ## Redirect
266
267 You can redirect to a new url
268
269 ``` ruby
270 redirect "/new_url"
271 ```
272
273 use permanent redirect
274
275 ``` ruby
c7ad0a4 @allenwei use hash argument in redirect
allenwei authored
276 redirect "/new_url", :permanent => true
7e49d27 @allenwei support permanent redirect, add document in readme
allenwei authored
277 ```
e536bde @jch add helpers to README
jch authored
278
09e7078 @dblock Supporting hash objects in error.
dblock authored
279 ## Raising Errors
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
280
09e7078 @dblock Supporting hash objects in error.
dblock authored
281 You can raise errors explicitly.
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
282
e61c905 @dblock Fixed typo.
dblock authored
283 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
284 error!("Access Denied", 401)
285 ```
09e7078 @dblock Supporting hash objects in error.
dblock authored
286
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
287 You can also return JSON formatted objects explicitly by raising error! and
288 passing a hash instead of a message.
09e7078 @dblock Supporting hash objects in error.
dblock authored
289
e61c905 @dblock Fixed typo.
dblock authored
290 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
291 error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
292 ```
09e7078 @dblock Supporting hash objects in error.
dblock authored
293
294 ## Exception Handling
295
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
296 Grape can be told to rescue all exceptions and instead return them in
297 text or json formats.
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
298
e61c905 @dblock Fixed typo.
dblock authored
299 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
300 class Twitter::API < Grape::API
301 rescue_from :all
302 end
303 ```
c0ce92e @dblock Clarified error format and handling.
dblock authored
304
305 You can also rescue specific exceptions.
306
e61c905 @dblock Fixed typo.
dblock authored
307 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
308 class Twitter::API < Grape::API
309 rescue_from ArgumentError, NotImplementedError
310 end
311 ```
c0ce92e @dblock Clarified error format and handling.
dblock authored
312
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
313 The error format can be specified using `error_format`. Available formats are
314 `:json` and `:txt` (default).
c0ce92e @dblock Clarified error format and handling.
dblock authored
315
e61c905 @dblock Fixed typo.
dblock authored
316 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
317 class Twitter::API < Grape::API
318 error_format :json
319 end
320 ```
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
321
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
322 You can rescue all exceptions with a code block. The `rack_response` wrapper
323 automatically sets the default error code and content-type.
197759b @dblock Extended rescue_from to take a block.
dblock authored
324
e61c905 @dblock Fixed typo.
dblock authored
325 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
326 class Twitter::API < Grape::API
327 rescue_from :all do |e|
328 rack_response({ :message => "rescued from #{e.class.name}" })
329 end
330 end
331 ```
197759b @dblock Extended rescue_from to take a block.
dblock authored
332
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
333 You can also rescue specific exceptions with a code block and handle the Rack
334 response at the lowest level.
197759b @dblock Extended rescue_from to take a block.
dblock authored
335
e61c905 @dblock Fixed typo.
dblock authored
336 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
337 class Twitter::API < Grape::API
338 rescue_from :all do |e|
339 Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
340 end
341 end
342 ```
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
343
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
344 Or rescue specific exceptions.
345
e61c905 @dblock Fixed typo.
dblock authored
346 ``` ruby
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
347 class Twitter::API < Grape::API
348 rescue_from ArgumentError do |e|
349 Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
350 end
351 rescue_from NotImplementedError do |e|
352 Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500)
353 end
354 end
355 ```
77efa30 @dblock Fixed rescue_from for multiple exceptions.
dblock authored
356
b43a608 @ppadron closes #82: adding specs and docs for logging support
ppadron authored
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
aec9444 @joeyAghion mention #content_types in README
joeyAghion authored
402 ## Content-Types
403
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
404 By default, Grape supports _XML_, _JSON_, _Atom_, _RSS_, and _text_ content-types.
405 Your API can declare additional types to support. Response format is determined by the
f0d03c2 @dblock Clarified mounting in Rails and Rack.
dblock authored
406 request's extension or `Accept` header.
aec9444 @joeyAghion mention #content_types in README
joeyAghion authored
407
e61c905 @dblock Fixed typo.
dblock authored
408 ``` ruby
aec9444 @joeyAghion mention #content_types in README
joeyAghion authored
409 class Twitter::API < Grape::API
aea29fd @joeyAghion define #content_type instead of ambiguous #content_types
joeyAghion authored
410 content_type :xls, "application/vnd.ms-excel"
aec9444 @joeyAghion mention #content_types in README
joeyAghion authored
411 end
412 ```
413
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
414 You can also set the default format. The order for choosing the format is the following.
415
416 * Use the file extension, if specified. If the file is .json, choose the JSON format.
5f5cdce @dblock Added both format and default_format.
dblock authored
417 * Use the format, if specified by the `format` option.
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
418 * Attempt to find an acceptable format from the `Accept` header.
5f5cdce @dblock Added both format and default_format.
dblock authored
419 * Use the default format, if specified by the `default_format` option.
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
420 * Default to `:txt` otherwise.
421
e61c905 @dblock Fixed typo.
dblock authored
422 ``` ruby
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
423 class Twitter::API < Grape::API
5f5cdce @dblock Added both format and default_format.
dblock authored
424 format :json
e61c905 @dblock Fixed typo.
dblock authored
425 default_format :json
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
426 end
427 ```
428
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
429 ## Writing Tests
430
9b63d92 @dblock Documented testing with RACK.
dblock authored
431 You can test a Grape API with RSpec by making HTTP requests and examining the response.
432
433 ### Writing Tests with Rack
434
435 Use `rack-test` and define your API as `app`.
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
436
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
437 ```ruby
9b63d92 @dblock Documented testing with RACK.
dblock authored
438 require 'spec_helper'
439
440 describe Twitter::API do
441 include Rack::Test::Methods
442
443 def app
444 Twitter::API
445 end
446
447 describe Twitter::API do
448 describe "GET /api/v1/statuses" do
449 it "returns an empty array of statuses" do
450 get "/api/v1/statuses"
451 last_response.status.should == 200
452 JSON.parse(response.body).should == []
453 end
454 end
455 describe "GET /api/v1/statuses/:id" do
456 it "returns a status by id" do
457 status = Status.create!
458 get "/api/v1/statuses/#{status.id}"
8e0203d @bowsersenior Fix a little typo in the README
bowsersenior authored
459 last_response.body.should == status.to_json
9b63d92 @dblock Documented testing with RACK.
dblock authored
460 end
461 end
462 end
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
463 end
464 ```
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
465
9b63d92 @dblock Documented testing with RACK.
dblock authored
466 ### Writing Tests with Rails
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
467
e61c905 @dblock Fixed typo.
dblock authored
468 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
469 require 'spec_helper'
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
470
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
471 describe Twitter::API do
472 describe "GET /api/v1/statuses" do
473 it "returns an empty array of statuses" do
474 get "/api/v1/statuses"
475 response.status.should == 200
476 JSON.parse(response.body).should == []
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
477 end
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
478 end
4d8a594 @dblock More doc changes, spellcheck.
dblock authored
479 describe "GET /api/v1/statuses/:id" do
480 it "returns a status by id" do
481 status = Status.create!
482 get "/api/v1/statuses/#{status.id}"
483 resonse.body.should == status.to_json
484 end
485 end
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
486 end
487 ```
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
488
9b63d92 @dblock Documented testing with RACK.
dblock authored
489 In Rails, HTTP request tests would go into the `spec/request` group. You may want your API code to go into
490 `app/api` - you can match that layout under `spec` by adding the following in `spec/spec_helper.rb`.
491
492 ```ruby
493 RSpec.configure do |config|
494 config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
495 :file_path => /spec\/api/
496 }
497 end
498 ```
499
04d7efd @flah00 updated documentation for entities
flah00 authored
500 ## Reusable Responses with Entities
501
44dd623 @flah00 possibly improved docs
flah00 authored
502 Entities are a reusable means for converting Ruby objects to API responses.
04d7efd @flah00 updated documentation for entities
flah00 authored
503 Entities can be used to conditionally include fields, nest other entities, and build
504 ever larger responses, using inheritance.
505
506 ### Defining Entities
507
44dd623 @flah00 possibly improved docs
flah00 authored
508 Entities inherit from Grape::Entity, and define a simple DSL. Exposures can use
509 runtime options to determine which fields should be visible, these options are
510 available to :if, :unless, and :proc. The option keys :version and :collection
511 will always be defined. The :version key is defined as api.version. The
512 :collection key is boolean, and defined as true if the object presented is an
513 array.
04d7efd @flah00 updated documentation for entities
flah00 authored
514
44dd623 @flah00 possibly improved docs
flah00 authored
515 * `expose SYMBOLS`
04d7efd @flah00 updated documentation for entities
flah00 authored
516 * define a list of fields which will always be exposed
44dd623 @flah00 possibly improved docs
flah00 authored
517 * `expose SYMBOLS, HASH`
04d7efd @flah00 updated documentation for entities
flah00 authored
518 * HASH keys include :if, :unless, :proc, :as, :using, :format_with, :documentation
519 * :if and :unless accept hashes (passed during runtime) or procs (arguments are object and options)
44dd623 @flah00 possibly improved docs
flah00 authored
520 * `expose SYMBOL, {:format_with => :formatter}`
04d7efd @flah00 updated documentation for entities
flah00 authored
521 * expose a value, formatting it first
44dd623 @flah00 possibly improved docs
flah00 authored
522 * :format_with can only be applied to one exposure at a time
523 * `expose SYMBOL, {:as => "alias"}`
04d7efd @flah00 updated documentation for entities
flah00 authored
524 * Expose a value, changing its hash key from SYMBOL to alias
44dd623 @flah00 possibly improved docs
flah00 authored
525 * :as can only be applied to one exposure at a time
526 * `expose SYMBOL BLOCK`
04d7efd @flah00 updated documentation for entities
flah00 authored
527 * block arguments are object and options
528 * expose the value returned by the block
44dd623 @flah00 possibly improved docs
flah00 authored
529 * block can only be applied to one exposure at a time
04d7efd @flah00 updated documentation for entities
flah00 authored
530
531 ``` ruby
532 module API
533 module Entities
534 class User < Grape::Entity
535 expose :first_name, :last_name
536 expose :field, :documentation => {:type => "string", :desc => "words go here"}
537 expose :email, :if => {:type => :full}
538 expose :user_type, user_id, :if => lambda{|user,options| user.confirmed?}
539 expose(:name){|user,options| [user.first_name, user.last_name].join(' ')}
540 expose :latest_status, :using => API::Status, :as => :status
541 end
542 end
543 end
544
545 module API
546 module Entities
547 class UserDetailed < API::Entities::User
548 expose :account_id
549 end
550 end
551 end
552 ```
553
554 ### Using Entities
555
556 Once an entity is defined, it can be used within endpoints, by calling #present. The #present
557 method accepts two arguments, the object to be presented and the options associated with it. The
558 options hash must always include :with, which defines the entity to expose.
559
560 If the entity includes documentation it can be included in an endpoint's description.
561
562 ``` ruby
563 module API
564 class Users < Grape::API
565 version 'v1'
566
567 desc 'User index', {
568 :object_fields => API::Entities::User.documentation
569 }
570 get '/users' do
571 @users = User.all
572 type = current_user.admin? ? :full : :default
573 present @users, with: API::Entities::User, :type => type
574 end
575 end
576 end
577 ```
578
3de8bf5 @flah00 entity caveats
flah00 authored
579 ### Caveats
580
581 Entities with duplicate exposure names and conditions will silently overwrite one another.
582 In the following example, when object#check equals "foo", only afield will be exposed.
583 However, when object#check equals "bar" both bfield and foo will be exposed.
584
585 ```ruby
586 module API
587 module Entities
588 class User < Grape::Entity
589 expose :afield, :foo, :if => lambda{|object,options| object.check=="foo"}
590 expose :bfield, :foo, :if => lambda{|object,options| object.check=="bar"}
591 end
592 end
593 end
594 ```
595
596 This can be problematic, when you have mixed collections. Using #respond_to? is safer.
597
598 ```ruby
599 module API
600 module Entities
601 class User < Grape::Entity
602 expose :afield, :if => lambda{|object,options| object.check=="foo"}
603 expose :bfield, :if => lambda{|object,options| object.check=="bar"}
604 expose :foo, :if => lambda{object,options| object.respond_to?(:foo)}
605 end
606 end
607 end
608 ```
609
17ec92c @dblock Added support for API descriptors.
dblock authored
610 ## Describing and Inspecting an API
37e0b79 @dblock Initial cut for structure layout.
dblock authored
611
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
612 Grape lets you add a description to an API along with any other optional
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
613 elements that can also be inspected at runtime.
04d7efd @flah00 updated documentation for entities
flah00 authored
614 This can be useful for generating documentation. If the response
615 requires documentation, consider using an entity.
37e0b79 @dblock Initial cut for structure layout.
dblock authored
616
e61c905 @dblock Fixed typo.
dblock authored
617 ``` ruby
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
618 class TwitterAPI < Grape::API
37e0b79 @dblock Initial cut for structure layout.
dblock authored
619
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
620 version 'v1'
17ec92c @dblock Added support for API descriptors.
dblock authored
621
622 desc "Retrieves the API version number."
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
623 get "version" do
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
624 api.version
625 end
37e0b79 @dblock Initial cut for structure layout.
dblock authored
626
52f8398 @dblock Added route that retrieves the information about the current route.
dblock authored
627 desc "Reverses a string.", { :params =>
17ec92c @dblock Added support for API descriptors.
dblock authored
628 { "s" => { :desc => "string to reverse", :type => "string" }}
2f46a71 @dblock Fixed desc to take only hashes.
dblock authored
629 }
17ec92c @dblock Added support for API descriptors.
dblock authored
630 get "reverse" do
631 params[:s].reverse
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
632 end
633 end
17ec92c @dblock Added support for API descriptors.
dblock authored
634 ```
37e0b79 @dblock Initial cut for structure layout.
dblock authored
635
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
636 Grape then exposes arrays of API versions and compiled routes. Each route
637 contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`,
638 `route_path` and `route_params`. The description and the optional hash that
639 follows the API path may contain any number of keys and its values are also
640 accessible via dynamically-generated `route_[name]` functions.
17ec92c @dblock Added support for API descriptors.
dblock authored
641
e61c905 @dblock Fixed typo.
dblock authored
642 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
643 TwitterAPI::versions # yields [ 'v1', 'v2' ]
644 TwitterAPI::routes # yields an array of Grape::Route objects
645 TwitterAPI::routes[0].route_version # yields 'v1'
17ec92c @dblock Added support for API descriptors.
dblock authored
646 TwitterAPI::routes[0].route_description # yields [ { "s" => { :desc => "string to reverse", :type => "string" }} ]
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
647 ```
4c834f5 @dblock Allowing arbitrary option hashes along with the api declaration.
dblock authored
648
17ec92c @dblock Added support for API descriptors.
dblock authored
649 Parameters can also be tagged to the method declaration itself.
4c834f5 @dblock Allowing arbitrary option hashes along with the api declaration.
dblock authored
650
e61c905 @dblock Fixed typo.
dblock authored
651 ``` ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
652 class StringAPI < Grape::API
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
653 get "split/:string", { :params => [ "token" ], :optional_params => [ "limit" ] } do
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
654 params[:string].split(params[:token], (params[:limit] || 0))
655 end
656 end
4c834f5 @dblock Allowing arbitrary option hashes along with the api declaration.
dblock authored
657
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
658 StringAPI::routes[0].route_params # yields an array [ "string", "token" ]
659 StringAPI::routes[0].route_optional_params # yields an array [ "limit" ]
660 ```
37e0b79 @dblock Initial cut for structure layout.
dblock authored
661
52f8398 @dblock Added route that retrieves the information about the current route.
dblock authored
662 It's possible to retrieve the information about the current route from within an API call with `route`.
663
e61c905 @dblock Fixed typo.
dblock authored
664 ``` ruby
52f8398 @dblock Added route that retrieves the information about the current route.
dblock authored
665 class MyAPI < Grape::API
666 desc "Returns a description of a parameter.", { :params => { "id" => "a required id" } }
667 get "params/:id" do
668 route.route_params[params[:id]] # returns "a required id"
669 end
670 end
671 ```
672
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
673 ## Anchoring
674
675 Grape by default anchors all request paths, which means that the request URL
676 should match from start to end to match, otherwise a `404 Not Found` is
677 returned.
678 However, this is sometimes not what you want, because it is not always known up
679 front what can be expected from the call.
680 This is because Rack-mount by default anchors requests to match from the start
681 to the end, or not at all. Rails solves this problem by using a `:anchor =>
682 false` option in your routes.
683 In Grape this option can be used as well when a method is defined.
684
685 For instance when you're API needs to get part of an URL, for instance:
686
e61c905 @dblock Fixed typo.
dblock authored
687 ``` ruby
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
688 class UrlAPI < Grape::API
689 namespace :urls do
690 get '/(*:url)', :anchor => false do
691 some_data
692 end
693 end
694 end
695 ```
696
697 This will match all paths starting with '/urls/'. There is one caveat though:
698 the `params[:url]` parameter only holds the first part of the request url.
699 Luckily this can be circumvented by using the described above syntax for path
700 specification and using the `PATH_INFO` Rack environment variable, using
948917e @dblock Spellcheck.
dblock authored
701 `env["PATH_INFO"]`. This will hold everything that comes after the '/urls/'
13ec78c @jwkoelewijn Added anchoring to Frontier branch (anchoring now in Endpoints class)
jwkoelewijn authored
702 part.
703
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
704 ## Note on Patches/Pull Requests
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
705
bcf5ad8 @dblock Explicitly set license type and updated contributor README.
dblock authored
706 * Fork the project
707 * Write tests for your new feature or a test that reproduces a bug
708 * Implement your feature or make a bug fix
709 * Do not mess with Rakefile, version or history
710 * Commit, push and make a pull request. Bonus points for topical branches.
711
712 ## License
713
714 MIT License. See LICENSE for details.
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
715
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
716 ## Copyright
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
717
d0644ec @dblock Allowing default_format to be meaningful.
dblock authored
718 Copyright (c) 2010-2012 Michael Bleigh and Intridea, Inc.
bcf5ad8 @dblock Explicitly set license type and updated contributor README.
dblock authored
719
Something went wrong with that request. Please try again.