Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 360 lines (256 sloc) 16.798 kb
3f957e4 @Sutto Add Gemnasium status
authored
1 # RocketPants! [![Build Status](https://secure.travis-ci.org/filtersquad/rocket_pants.png?branch=master)](http://travis-ci.org/filtersquad/rocket_pants) [![Dependency Status](https://gemnasium.com/filtersquad/rocket_pants.png)](https://gemnasium.com/filtersquad/rocket_pants)
2
22b6142 @Sutto More readme tweaks.
authored
3 ## Introduction
4
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
5 First thing's first, you're probably asking yourself - "Why the ridiculous name?". It's simple, really - RocketPants is memorable, and sounds completely bad ass. - everything a library needs.
98d2351 @Sutto README work and License tweaks
authored
6
5e788d8 @levibuzolic Fixed typo in README
levibuzolic authored
7 At its core, RocketPants is a set of tools (built around existing toolsets such as ActionPack) to make it easier to build well-designed APIs in Ruby and more importantly, along side Rails. You can think of it like [Grape](https://github.com/intridea/grape), a fantastic library which RocketPants was originally inspired by but with deeper Rails and ActionPack integration.
98d2351 @Sutto README work and License tweaks
authored
8
9 ## Key Features
10
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
11 Why use RocketPants over alternatives like Grape or normal Rails? The reasons we built it come down to a couple of simple things:
98d2351 @Sutto README work and License tweaks
authored
12
13 1. **It's opinionated** (like Grape) - In this case, we dictate a certain JSON structure we've found nice to work with (after having worked with and investigated a large number of other apis), it makes it simple to add metadata along side requests and the like.
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
14 2. **Simple and Often Automatic Response Metadata** - RocketPants automatically takes care of sending metadata about paginated responses and arrays where possible. This means as a user, you only need to worry about writing `expose object_or_presenter` in your controller and RocketPants will do it's best to send as much information back to the user.
15 3. **Extended Error Support** - RocketPants has a built in framework to manage errors it knows how to handle (in the forms of mapping exceptions to a well defined JSON structure) as well as tools to make it simple to hook up to Airbrake and do things such as including an error identifier in the response.
16 4. **It's built on ActionPack** - One of the key differentiators to Grape is that RocketPants embraces ActionPack and uses the modular components included from Rails 3.0 onwards to provide things you're familiar with already such as filters.
17 5. **Semi-efficient Caching Support** - Thanks to a combination of Rails middleware and collection vs. resource distinctions, RocketPants makes it relatively easy to implement "Efficient Validation" (See [here](http://rtomayko.github.com/rack-cache/faq)). As a developer, this means you get even more benefits of http caching where possible, without the need to generate full requests when etags are present.
98d2351 @Sutto README work and License tweaks
authored
18
22b6142 @Sutto More readme tweaks.
authored
19 ## Examples
20
21 ### A full example application
74b4567 @Sutto Add link to example app (not yet there)
authored
22
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
23 Learn better by reading code? There is also have an example app mixing models and api clients over at [Sutto/transperth-api](https://github.com/Sutto/transperth-api) that is built using RocketPants.
74b4567 @Sutto Add link to example app (not yet there)
authored
24
22b6142 @Sutto More readme tweaks.
authored
25 ### Example controllers
26
7a362ce @Sutto More tweaks! Namely to the README
authored
27 Say, for example, you have a basic Food model:
22b6142 @Sutto More readme tweaks.
authored
28
29 ```ruby
7a362ce @Sutto More tweaks! Namely to the README
authored
30 class Food < ActiveRecord::Base
31 include RocketPants::Cacheable
32 end
33 ```
34
35 ```ruby
36 class FoodsController < RocketPants::Base
37
38 version 1
39
40 # The list of foods is paginated for 5 minutes, the food itself is cached
41 # until it's modified (using Efficient Validation)
42 caches :index, :show, :caches_for => 5.minutes
22b6142 @Sutto More readme tweaks.
authored
43
44 def index
7a362ce @Sutto More tweaks! Namely to the README
authored
45 expose Food.paginate(:page => params[:page])
22b6142 @Sutto More readme tweaks.
authored
46 end
47
48 def show
7a362ce @Sutto More tweaks! Namely to the README
authored
49 expose Food.find(params[:id])
22b6142 @Sutto More readme tweaks.
authored
50 end
51
52 end
53 ```
54
55 And in the router we'd just use the normal REST-like routes in Rails:
56
57 ```ruby
7a362ce @Sutto More tweaks! Namely to the README
authored
58 api :version => 1 do
59 resources :foods, :only => [:index, :show]
60 end
61 ```
62
63 And then, using this example, hitting `GET http://localhost:3000/foods` would result in:
64
65 ```json
66 {
67 "response": [{
68 "id": 1,
69 "name": "Delicious Food"
70 }, {
71 "id": 2,
72 "name": "More Delicious Food"
73 }],
74 "count": 2,
75 "pagination": {
76 "previous": nil,
77 "next": nil,
78 "current": 1,
79 "per_page": 10,
80 "count": 2,
81 "pages": 1
82 }
83 }
22b6142 @Sutto More readme tweaks.
authored
84 ```
85
7a362ce @Sutto More tweaks! Namely to the README
authored
86 with the `Cache-Control` header set whilst hitting `GET http://localhost:3000/foods/1` would return:
87
88 ```json
89 {
90 "response": {
91 "id": 1,
92 "name": "Delicious Food"
93 }
94 }
95 ```
96
97 with the `Etag` header set.
98
98d2351 @Sutto README work and License tweaks
authored
99 ## General Structure
100
101 RocketPants builds upon the mixin-based approach to ActionController-based rails applications that Rails 3 made possible. Instead of including everything like Rails does in `ActionController::Base`, RocketPants only includes the bare minimum to make apis. In the near future, it may be modified to work with `ActionController::Base` for the purposes of better compatibility with other gems.
102
103 Out of the box, we use the following ActionController components:
104
105 * `ActionController::HideActions` - Lets you hide methods from actions.
106 * `ActionController::UrlFor` - `url_for` helpers / tweaks by Rails to make integration with routes work better.
107 * `ActionController::Redirecting` - Allows you to use `redirect_to`.
108 * `ActionController::ConditionalGet` - Adds support for Rails caching controls, e.g. `fresh_when` and `expires_in`.
109 * `ActionController::RackDelegation` - Lets you reset the session and set the response body.
110 * `ActionController::RecordIdentifier` - Gives `dom_class` and `dom_id` methods, used for polymorphic routing.
111 * `ActionController::MimeResponds` - Gives `respond_to` with mime type controls.
112 * `AbstractController::Callbacks` - Adds support for callbacks / filters.
113 * `ActionController::Rescue` - Lets you use `rescue_from`.
114
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
115 And added our own:
98d2351 @Sutto README work and License tweaks
authored
116
117 * `RocketPants::UrlFor` - Automatically includes the current version when generating URLs from the controller.
118 * `RocketPants::Respondable` - The core of RocketPants, the code that handles converting objects to the different container types.
119 * `RocketPants::Versioning` - Allows versioning requirements on the controller to ensure it is only callable with a specific api version.
120 * `RocketPants::Instrumentation` - Adds Instrumentation notifications making it easy to use and hook into with Rails.
121 * `RocketPants::Caching` - Implements time-based caching for index actions and etag-based efficient validation for singular resources.
122 * `RocketPants::ErrorHandling` - Short hand to create errors as well as simplifications to catch and render a standardised error representation.
123 * `RocketPants::Rescuable` - Allows you to hook in to rescuing exceptions and to make it easy to post notifications to tools such as AirBrake.
124
125 To use RocketPants, instead of inheriting from `ActionController::Base`, just inherit from `RocketPants::Base`.
126
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
127 Likewise, in Rails applications RocketPants also adds `RocketPants::CacheMiddleware` before the controller endpoints to implement ["Efficient Validation"](http://rtomayko.github.com/rack-cache/faq).
98d2351 @Sutto README work and License tweaks
authored
128
149db46 @Sutto More README docs / tweaks
authored
129 ## Installing RocketPants
130
131 Installing RocketPants is a simple matter of adding:
132
133 gem 'rocket_pants', '~> 1.0'
134
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
135 To your `Gemfile` and running `bundle install`. Next, instead of inherited from `ActionController::Base`, simply inherit from `RocketPants::Base` instead. If you're working with an API-only application, I typically change this in `ApplicationController` and inherit from `ApplicationController` as usual. Otherwise, I generate a new `ApiController` base controller along side `ApplicationController` which instead inherits from `RocketPants::Base` and place all my logic there.
149db46 @Sutto More README docs / tweaks
authored
136
137 ## Configuration
138
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
139 Setting up RocketPants in your rails application is pretty simple and requires a minimal amount of effort. Inside your environment configuration, RocketPants offers the following options to control how it's configured (and their expanded alternatives):
149db46 @Sutto More README docs / tweaks
authored
140
141 - `config.rocket_pants.use_caching` - Defaulting to true for production environments and false elsewhere, defines whether RocketPants caching setup as described below is used.
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
142 - `config.rocket_pants.cache` - A `Moneta::Store` instance used as the RocketPants cache, defaulting to a moneta memory instance. Change for proper caching. (See [here](https://github.com/wycats/moneta) for more information on Moneta.)
149db46 @Sutto More README docs / tweaks
authored
143
144 ## Version Controllers / Routes
145
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
146 The current preferred way of dealing with version APIs in RocketPants is to do it using routes in the form of `/:version/:endpoint` - e.g. `GET /1/users/324`. RocketPants has support in the router and controller level for enforcing and controlling this. In the controller, it's a matter of specifying the required API versions:
149db46 @Sutto More README docs / tweaks
authored
147
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
148 ```ruby
149 class UsersController < RocketPants::Base
150 version 1 # A single version
151 # or...
152 version 2..3 # 2-3 support this controller
153 end
154 ```
149db46 @Sutto More README docs / tweaks
authored
155
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
156 And in the case of multiple versions, I strongly encourage namespaces the controllers inside modules. If the version param (as specified) by the URL does not match, then the specified controller will return an `:invalid_version` error as shown below.
149db46 @Sutto More README docs / tweaks
authored
157
158 Next, in your `config/routes.rb` file, you can also declare versions using the following syntax and it will automatically set up the routes for you:
159
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
160 ```ruby
161 api :version => 1 do
162 get 'x', :to => 'test#item'
163 end
164 ```
149db46 @Sutto More README docs / tweaks
authored
165
166 Which will route `GET /1/x` to `TestController#item`.
167
168 Likewise, you can specify a route for multiple versions by:
169
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
170 ```ruby
171 api :versions => 1..3 do
172 get 'x', :to => 'test#item'
173 end
174 ```
149db46 @Sutto More README docs / tweaks
authored
175
98d2351 @Sutto README work and License tweaks
authored
176 ## Working with data
177
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
178 When using RocketPants, you write your controllers the same as how you would with normal ActionController, the only thing that changes is how you handle data. `head` and `redirect_to` still work exactly the same as in Rails, but instead of using `respond_with` and `render` you instead use RocketPant's `exposes` methods (and it's kind). Namely:
3f8d609 @Sutto More type conversion docs
authored
179
180 - `expose` / `exposes` - The core of all type conversion, will check the type of data and automatically convert it to the correct time (for either a singular, collection or paginated resource).
181 - `paginated` - Render an object as a paginated collection of data.
182 - `collection` - Renders a collection of objects - e.g. an array of users.
183 - `resource` - Renders a single object.
184
185 Along side the above that wrap data, it also provides:
186
187 - `responds` - Renders JSON, normalizing the object first (unwrapped).
188 - `render_json` - Renders an object as JSON.
189
190 ### Singular Resources
191
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
192 Singular resources will be converted to JSON via `serializable_hash`, passing through any objects
3f8d609 @Sutto More type conversion docs
authored
193 and then wrapped in an object as the `response` key:
194
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
195 ```json
196 {
197 "response": {
198 "your": "serialized-object"
199 }
200 }
201 ```
3f8d609 @Sutto More type conversion docs
authored
202
203 ### Collections
204
205 Similar to singular resources, but also include extra data about the count of items.
206
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
207 ```json
208 {
209 "response": [{
210 "name": "object-one"
211 }, {
212 "name": "object-two"
213 }],
214 "count": 2
215 }
216 ```
3f8d609 @Sutto More type conversion docs
authored
217
218 ### Paginated Collections
219
220 The final type, similar to paginated objects but it includes details about the paginated data:
221
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
222 ```json
223 {
224 "response": [
225 {"name": "object-one"},
226 {"name": "object-two"},
227 {"name": "object-three"},
228 {"name": "object-four"},
229 {"name": "object-five"}
230 ],
231 "count": 5,
232 "pagination": {
233 "previous": 1,
234 "next": 3,
235 "current": 2,
236 "per_page": 5,
1e498dc @levibuzolic Missing comma in paginated collections example
levibuzolic authored
237 "count": 23,
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
238 "pages": 5
239 }
240 }
241 ```
98d2351 @Sutto README work and License tweaks
authored
242
243 ## Registering / Dealing with Errors
244
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
245 One of the built in features of RocketPants is the ability to handle rescuing / controlling exceptions and more importantly to handle mapping exceptions to names, messages and error codes.
4da07ec @Sutto Started writing docs on the error handling
authored
246
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
247 This comes in useful when you wish to automatically convert exceptions such as `ActiveRecord::RecordNotFound` to a structured bit of data in the response. Namely, it makes it trivial to generate objects that follow the JSON structure of:
4da07ec @Sutto Started writing docs on the error handling
authored
248
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
249 ```json
250 {
251 "error": "standard_error_name",
252 "error_description": "A translated error message describing what happened."
253 }
254 ```
4da07ec @Sutto Started writing docs on the error handling
authored
255
256 It also adds a facilities to make it easy to add extra information to the response.
257
258 RocketPants will also attempt to convert all errors in the controller, defaulting to the `"system"` exception name and message as the error description. We also provide a registry to allow throwing exception from their symbolic name like so:
259
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
260 ```ruby
261 error! :not_found
262 ```
4da07ec @Sutto Started writing docs on the error handling
authored
263
264 In the controller.
265
266 Out of the box, the following exceptions come pre-registered and setup:
267
268 - `:throttled` - The user has hit an api throttled error.
269 - `:unauthenticated` - The user doesn't have valid authentication details.
270 - `:invalid_version` - An invalid API version was specified.
271 - `:not_implemented` - The specified endpoint is not yet implemented.
272 - `:not_found` - The given resource could not be found.
273
98d2351 @Sutto README work and License tweaks
authored
274 ## Implementing Efficient Validation
275
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
276 One of the core design principles built into RocketPants is simple support for "Efficient Validation" as described in the [Rack::Cache FAQ](http://rtomayko.github.com/rack-cache/faq) - Namely, it adds simple support for object-level caching using etags with fast verification thanks to the `RocketPants::CacheMiddleware` cache middleware.
149db46 @Sutto More README docs / tweaks
authored
277
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
278 To do this, it uses `RocketPants.cache`, by default any Moneta-based store, to keep a mapping of object -> current cache key. RocketPants will then generate the etag when caching is enabled in the controller for singular-responses, generating an etag that can be quickly validated.
149db46 @Sutto More README docs / tweaks
authored
279
280 For example, you'd add the following to your model:
281
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
282 ```ruby
283 class User < ActiveRecord::Base
284 include RocketPants::Cacheable
285 end
286 ```
149db46 @Sutto More README docs / tweaks
authored
287
288 And then in your controller, you'd have something like:
289
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
290 ```ruby
291 class UsersController < RocketPants::Base
149db46 @Sutto More README docs / tweaks
authored
292
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
293 version 1
149db46 @Sutto More README docs / tweaks
authored
294
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
295 # Time based, e.g. collections, will be cached for 5 minutes - whilst singular
296 # items e.g. show will use etag-based caching:
297 caches :show, :index, :caches_for => 5.minutes
149db46 @Sutto More README docs / tweaks
authored
298
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
299 def index
300 expose User.all
301 end
149db46 @Sutto More README docs / tweaks
authored
302
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
303 def show
304 expose User.find(params[:id])
305 end
149db46 @Sutto More README docs / tweaks
authored
306
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
307 end
308 ```
149db46 @Sutto More README docs / tweaks
authored
309
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
310 When the user hits the index endpoint, it will generate an expiry-based caching header that caches the result for up to 5 minutes. When the user instead hits the show endpoint, it will generate a special etag that contains and object identifier portion and an object cache key. Inside `RocketPants.cache`, we store the mapping and then inside `RocketPants::CacheMiddleware`, we simply check if the given cache key matches the specified object identifier. If it does, we return a not modified response otherwise we pass it through to controller - giving the advantage of efficient caching without having to hit the full database on every request.
98d2351 @Sutto README work and License tweaks
authored
311
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
312 ## Using with RSpec
73b2f4e Add misc. test helpers
Darcy Laycock authored
313
98d2351 @Sutto README work and License tweaks
authored
314 RocketPants includes a set of helpers to make testing controllers built on `RocketPants::Base` simpler.
315
19b8bc5 @Sutto RSpec integration docs
authored
316 * `be_singular_resource` - Checks the response is a single resource - e.g. `response.should be_siingular_resource`.
317 * `be_collection_resource` - Checks the response is collection of resources - e.g. `response.should be_collection_resource`.
318 * `be_paginated_response` - Checks the response is paginated - e.g. `response.should be_paginated_response`.
319 * `be_api_error(type = any)` - Checks it returned an error for the specified exception (or check the response is an error without any argument) - e.g. `response.should be_api_error RocketPants::NotFound`.
320 * `have_exposed(data, options = {})` - Given an object and conversion options, lets you check the output exposed the same object. e.g: `response.should have_exposed user`
321
322 Likewise, it adds the following helper methods:
323
324 - `parsed_body` - A parsed-JSON representation of the response.
325 - `decoded_body` - A `Hashie::Mash` of the response body.
326
327 To set up the integration, in your `spec/spec_helper.rb` add:
328
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
329 ```ruby
330 config.include RocketPants::TestHelper, :type => :controller
331 config.include RocketPants::RSpecMatchers, :type => :controller
332 ```
19b8bc5 @Sutto RSpec integration docs
authored
333
334 Inside the `RSpec.configure do |config|` block.
98d2351 @Sutto README work and License tweaks
authored
335
8ced3cb @Sutto Update README.md
authored
336 ## Contributors
337
338 - [Darcy Laycock](https://github.com/Sutto) - Main developer, current maintainer.
339 - [Steve Webb](https://github.com/swebb) - Helped with original work at [The Frontier Group](https://github.com/thefrontiergroup), inc. original design.
340 - [Fred Wu](https://github.com/fredwu) - README fixes.
341 - [Levi Buzolic](https://github.com/levibuzolic) - README fixes.
342
98d2351 @Sutto README work and License tweaks
authored
343 ## Contributing
344
345 We encourage all community contributions. Keeping this in mind, please follow these general guidelines when contributing:
346
347 * Fork the project
348 * Create a topic branch for what you’re working on (git checkout -b awesome_feature)
349 * Commit away, push that up (git push your\_remote awesome\_feature)
350 * Create a new GitHub Issue with the commit, asking for review. Alternatively, send a pull request with details of what you added.
351 * Once it’s accepted, if you want access to the core repository feel free to ask! Otherwise, you can continue to hack away in your own fork.
352
353 Other than that, our guidelines very closely match the GemCutter guidelines [here](http://wiki.github.com/qrush/gemcutter/contribution-guidelines).
354
355 (Thanks to [GemCutter](http://wiki.github.com/qrush/gemcutter/) for the contribution guide)
73b2f4e Add misc. test helpers
Darcy Laycock authored
356
98d2351 @Sutto README work and License tweaks
authored
357 ## License
73b2f4e Add misc. test helpers
Darcy Laycock authored
358
22b6142 @Sutto More readme tweaks.
authored
359 RocketPants is released under the MIT License (see the [license file](https://github.com/filtersquad/rocket_pants/blob/master/LICENSE)) and is copyright Filter Squad, 2012.
Something went wrong with that request. Please try again.