Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 315 lines (236 sloc) 9.037 kb
dfae958 @mbleigh Adds Frontier comment to README
mbleigh authored
1 # Grape (Frontier) [![Build Status](http://travis-ci.org/intridea/grape.png)](http://travis-ci.org/intridea/grape)
2
3 **Welcome to the `frontier` branch. This is where we're experimenting and building the next version of Grape. Things will be civilized here one day, but until then you best carry your revolver with you.**
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
4
5e16531 @dblock Added the project tracking section.
dblock authored
5 ## What is Grape?
6
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
7 Grape is a REST-like API micro-framework for Ruby. It is built to complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily provide APIs. It has built-in support for common conventions such as multiple formats, subdomain/prefix restriction, and versioning.
8
5e16531 @dblock Added the project tracking section.
dblock authored
9 ## Project Tracking
10
11 * [Grape Google Group](http://groups.google.com/group/ruby-grape)
12 * [Grape Wiki](https://github.com/intridea/grape/wiki)
13
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
14 ## Installation
15
16 Grape is available as a gem, to install it just install the gem:
17
18 gem install grape
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
19
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
20 ## Basic Usage
21
22 Grape APIs are Rack applications that are created by subclassing `Grape::API`. Below is a simple example showing some of the more common features of Grape in the context of recreating parts of the Twitter API.
23
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
24 ```ruby
25 class Twitter::API < Grape::API
a99ad72 @jch update README: default versioning strategy uses
jch authored
26 version 'v1', :using => :header, :vendor => 'twitter', :format => :json
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
27
28 helpers do
29 def current_user
30 @current_user ||= User.authorize!(env)
31 end
32
33 def authenticate!
34 error!('401 Unauthorized', 401) unless current_user
35 end
36 end
37
38 resource :statuses do
39 get :public_timeline do
40 Tweet.limit(20)
41 end
42
43 get :home_timeline do
44 authenticate!
45 current_user.home_timeline
46 end
47
48 get '/show/:id' do
49 Tweet.find(params[:id])
50 end
51
52 post :update do
53 authenticate!
54 Tweet.create(
55 :user => current_user,
56 :text => params[:status]
57 )
58 end
59 end
60
61 resource :account do
62 before{ authenticate! }
63
64 get '/private' do
65 "Congratulations, you found the secret!"
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
66 end
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
67 end
68 end
69 ```
70
1c25949 @imsaar fixed the readme file example code
imsaar authored
71 This would create a Rack application that could be used like so (in a Rackup config.ru file):
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
72
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
73 ```ruby
74 run Twitter::API
75 ```
76
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
77 And would respond to the following routes:
78
a99ad72 @jch update README: default versioning strategy uses
jch authored
79 GET /statuses/public_timeline(.json)
80 GET /statuses/home_timeline(.json)
81 GET /statuses/show/:id(.json)
82 POST /statuses/update(.json)
83
84 Versioning is handled with HTTP Accept head by default, but can be configures
85 to [use different
86 strategies](https://github.com/intridea/grape/wiki/API-Versioning). For
87 example, to request the above with a version, you would make the following
88 request:
89
90 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
91
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
92 By default, the first matching version is used when no Accept header is supplied. This behavior is similar to routing in Rails.
93 To circumvent this default behaviour, one could use the `:strict` option. When this option is set to `true`, a `404 Not found` error is returned when no correct Accept header is supplied.
94
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
95 Serialization takes place automatically. For more detailed usage information, please visit the [Grape Wiki](http://github.com/intridea/grape/wiki).
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
96
e536bde @jch add helpers to README
jch authored
97 ## Helpers
98
99 You can define helper methods that your endpoints can use with the `helpers`
100 macro by either giving a block or a module:
101
102 ````ruby
103 module MyHelpers
104 def say_hello(user)
105 "hey there #{user.name}"
106 end
107 end
108
109 class API < Grape::API
110 # define helpers with a block
111 helpers do
112 def current_user
113 User.find(params[:user_id])
114 end
115 end
116
117 # or mix in a module
118 helpers MyHelpers
119
120 get '/hello' do
121 # helpers available in your endpoint and filters
122 say_hello(current_user)
123 end
124 end
125 ````
126
127
c1deb71 @mbleigh Adds a blip about entities to the README
mbleigh authored
128 ## Working with Entities
129
130 A common problem in designing Ruby APIs is that you probably don't want
131 the exact structure of your data models exposed. ActiveRecord, for
132 instance, will dump all of its attributes. While you can override
133 `#as_json` to alter this behavior somewhat, what is really needed is an
134 intermediary layer between the model and the API. This is where the
135 `Grape::Entity` class comes in.
136
137 ```ruby
138 module Entities
139 class User < Grape::Entity
140 expose :first_name, :last_name
141 expose :email, :if => {:authenticated => true}
142 expose :name, :id => {:version => 'v1'} # deprecated
143 end
144 end
145
146 class API < Grape::API
147 version 'v1', 'v2'
148
149 get '/users/:id' do
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
150 present User.find(params[:id]),
c1deb71 @mbleigh Adds a blip about entities to the README
mbleigh authored
151 :with => Entities::User,
152 :authenticated => env.key?('api.token')
153 end
154 end
155 ```
156
157 For more information about Entities, view the project's YARD
158 documentation.
159
09e7078 @dblock Supporting hash objects in error.
dblock authored
160 ## Raising Errors
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
161
09e7078 @dblock Supporting hash objects in error.
dblock authored
162 You can raise errors explicitly.
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
163
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
164 ```ruby
165 error!("Access Denied", 401)
166 ```
09e7078 @dblock Supporting hash objects in error.
dblock authored
167
168 You can also return JSON formatted objects explicitly by raising error! and passing a hash instead of a message.
169
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
170 ```ruby
171 error!({ "error" => "unexpected error", "detail" => "missing widget" }, 500)
172 ```
09e7078 @dblock Supporting hash objects in error.
dblock authored
173
174 ## Exception Handling
175
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
176 Grape can be told to rescue all exceptions and instead return them in
177 text or json formats.
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
178
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
179 ```ruby
180 class Twitter::API < Grape::API
181 rescue_from :all
182 end
183 ```
c0ce92e @dblock Clarified error format and handling.
dblock authored
184
185 You can also rescue specific exceptions.
186
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
187 ```ruby
188 class Twitter::API < Grape::API
189 rescue_from ArgumentError, NotImplementedError
190 end
191 ```
c0ce92e @dblock Clarified error format and handling.
dblock authored
192
193 The error format can be specified using `error_format`. Available formats are `:json` and `:txt` (default).
194
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
195 ```ruby
196 class Twitter::API < Grape::API
197 error_format :json
198 end
199 ```
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
200
197759b @dblock Extended rescue_from to take a block.
dblock authored
201 You can rescue all exceptions with a code block. The `rack_response` wrapper automatically sets the default error code and content-type.
202
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
203 ```ruby
204 class Twitter::API < Grape::API
205 rescue_from :all do |e|
206 rack_response({ :message => "rescued from #{e.class.name}" })
207 end
208 end
209 ```
197759b @dblock Extended rescue_from to take a block.
dblock authored
210
211 You can also rescue specific exceptions with a code block and handle the Rack response at the lowest level.
212
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
213 ```ruby
214 class Twitter::API < Grape::API
215 rescue_from :all do |e|
216 Rack::Response.new([ e.message ], 500, { "Content-type" => "text/error" }).finish
217 end
218 end
219 ```
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
220
77efa30 @dblock Fixed rescue_from for multiple exceptions.
dblock authored
221 class Twitter::API < Grape::API
222 rescue_from ArgumentError do |e|
223 Rack::Response.new([ "ArgumentError: #{e.message}" ], 500)
224 end
225 rescue_from NotImplementedError do |e|
226 Rack::Response.new([ "NotImplementedError: #{e.message}" ], 500)
227 end
228 end
229
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
230 ## Writing Tests
231
232 You can test a Grape API with RSpec. Tests make HTTP requests, therefore they must go into the `spec/request` group. You may want your API code to go into `app/api` - you can match that layout under `spec` by adding the following in `spec/spec_helper.rb`.
233
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
234 ```ruby
235 RSpec.configure do |config|
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
236 config.include RSpec::Rails::RequestExampleGroup, :type => :request, :example_group => {
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
237 :file_path => /spec\/api/
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
238 }
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
239 end
240 ```
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
241
242 A simple RSpec API test makes a `get` request and parses the response.
243
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
244 ```ruby
245 require 'spec_helper'
732a8b4 @dblock Added a doc section on writing tests.
dblock authored
246
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
247 describe Twitter::API do
248 describe "GET /api/v1/statuses" do
249 it "returns an empty array of statuses" do
250 get "/api/v1/statuses"
251 response.status.should == 200
252 JSON.parse(response.body).should == []
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
253 end
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
254 end
255 end
256 ```
e3f5257 It's now possible to catch all exceptions thrown within APIs and to spec...
dB authored
257
17ec92c @dblock Added support for API descriptors.
dblock authored
258 ## Describing and Inspecting an API
37e0b79 @dblock Initial cut for structure layout.
dblock authored
259
2f46a71 @dblock Fixed desc to take only hashes.
dblock authored
260 Grape lets you add a description to an API along with any other optional elements that can also be inspected at runtime.
17ec92c @dblock Added support for API descriptors.
dblock authored
261 This can be useful for generating documentation.
37e0b79 @dblock Initial cut for structure layout.
dblock authored
262
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
263 ```ruby
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
264 class TwitterAPI < Grape::API
37e0b79 @dblock Initial cut for structure layout.
dblock authored
265
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
266 version 'v1'
17ec92c @dblock Added support for API descriptors.
dblock authored
267
268 desc "Retrieves the API version number."
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
269 get "version" do
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
270 api.version
271 end
37e0b79 @dblock Initial cut for structure layout.
dblock authored
272
2f46a71 @dblock Fixed desc to take only hashes.
dblock authored
273 desc "Reverses a string.", { :params =>
17ec92c @dblock Added support for API descriptors.
dblock authored
274 { "s" => { :desc => "string to reverse", :type => "string" }}
2f46a71 @dblock Fixed desc to take only hashes.
dblock authored
275 }
17ec92c @dblock Added support for API descriptors.
dblock authored
276 get "reverse" do
277 params[:s].reverse
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
278 end
279 end
17ec92c @dblock Added support for API descriptors.
dblock authored
280 ```
37e0b79 @dblock Initial cut for structure layout.
dblock authored
281
17ec92c @dblock Added support for API descriptors.
dblock authored
282 Grape then exposes arrays of API versions and compiled routes. Each route contains a `route_prefix`, `route_version`, `route_namespace`, `route_method`, `route_path` and `route_params`. The description and the optional hash that follows the API path may contain any number of keys and its values are also accessible via dynamically-generated `route_[name]` functions.
283
284 ```ruby
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
285 TwitterAPI::versions # yields [ 'v1', 'v2' ]
286 TwitterAPI::routes # yields an array of Grape::Route objects
287 TwitterAPI::routes[0].route_version # yields 'v1'
17ec92c @dblock Added support for API descriptors.
dblock authored
288 TwitterAPI::routes[0].route_description # yields [ { "s" => { :desc => "string to reverse", :type => "string" }} ]
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
289 ```
4c834f5 @dblock Allowing arbitrary option hashes along with the api declaration.
dblock authored
290
17ec92c @dblock Added support for API descriptors.
dblock authored
291 Parameters can also be tagged to the method declaration itself.
4c834f5 @dblock Allowing arbitrary option hashes along with the api declaration.
dblock authored
292
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
293 ```ruby
294 class StringAPI < Grape::API
d104c57 @jwkoelewijn Return 404 if no header is sent, but header based version is used and
jwkoelewijn authored
295 get "split/:string", { :params => [ "token" ], :optional_params => [ "limit" ] } do
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
296 params[:string].split(params[:token], (params[:limit] || 0))
297 end
298 end
4c834f5 @dblock Allowing arbitrary option hashes along with the api declaration.
dblock authored
299
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
300 StringAPI::routes[0].route_params # yields an array [ "string", "token" ]
301 StringAPI::routes[0].route_optional_params # yields an array [ "limit" ]
302 ```
37e0b79 @dblock Initial cut for structure layout.
dblock authored
303
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
304 ## Note on Patches/Pull Requests
12c522a @mbleigh Add fenced and highlighted code to README
mbleigh authored
305
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
306 * Fork the project.
307 * Make your feature addition or bug fix.
308 * Add tests for it. This is important so I don't break it in a future version unintentionally.
f510f0d @dblock Refactored api structure madness into api route collection.
dblock authored
309 * Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
310 * Send me a pull request. Bonus points for topic branches.
311
e690f37 @mbleigh Cleaning up the README a bit.
mbleigh authored
312 ## Copyright
01676ed @mbleigh Changed Endpoint to be a factory instead of a single class. Much more sa...
mbleigh authored
313
314 Copyright (c) 2010 Michael Bleigh and Intridea, Inc. See LICENSE for details.
Something went wrong with that request. Please try again.