Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 601 lines (452 sloc) 25.895 kB
5295431 @Sutto Reflect new contribution guide.
authored
1 # Rocket Pants! [![Build Status](https://secure.travis-ci.org/filtersquad/rocket_pants.png?branch=master)](http://travis-ci.org/filtersquad/rocket_pants)
3f957e4 @Sutto Add Gemnasium status
authored
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
8ef1f98 @Sutto More tweaks
authored
13 1. **[It's opinionated](#working-with-data)** (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.
14 2. **[Simple and Often Automatic Response Metadata](#collections)** - 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.
bf65cf1 @Sutto Update the docs
authored
15 3. **[Extended Error Support](#registering--dealing-with-errors)** - 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](#general-structure)** - 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](#implementing-efficient-validation)** - Thanks to a combination of Rails middleware and collection vs. resource distinctions, RocketPants makes it relatively easy to implement "Efficient Validation" (See [here](#implementing-efficient-validation)). 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.
18 6. **[Simple tools to consume RocketPants apis](#example-client-code)** - RocketPants includes the `RocketPants::Client` class which builds upon [APISmith](https://github.com/filtersquad/api_smith) to make it easier to build clients e.g. automatically converting paginated responses back.
19 7. **[Build in Header Metadata Support](#header-metadata)** - APIs can easily expose `Link:` headers (it's even partly built in for paginated data - see below) and request metadata (e.g. Object count etc) can easily be embedded in the headers of the response, making useful `HEAD` requests.
20 8. **[Out of the Box ActiveRecord mapping](#built-in-activerecord-errors)** - We'll automatically take care of mapping `ActiveRecord::RecordNotFound`, `ActiveRecord::RecordNotSaved` and `ActiveRecord::RecordInvalid` for you, even including validation messages where possible.
aae0b2f @Sutto Add a note to the README
authored
21 9. **[Support for active_model_serializers](https://github.com/rails-api/active_model_serializers)** - If you want to use ActiveModelSerializers, we'll take care of it. Even better, in your expose call, pass through `:serializer` as expected and we'll automatically take care of invoking it for you.
98d2351 @Sutto README work and License tweaks
authored
22
22b6142 @Sutto More readme tweaks.
authored
23 ## Examples
24
25 ### A full example application
74b4567 @Sutto Add link to example app (not yet there)
authored
26
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
27 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
28
0222651 @Sutto Add client examples
authored
29 ### Example Server Code
22b6142 @Sutto More readme tweaks.
authored
30
7a362ce @Sutto More tweaks! Namely to the README
authored
31 Say, for example, you have a basic Food model:
22b6142 @Sutto More readme tweaks.
authored
32
33 ```ruby
7a362ce @Sutto More tweaks! Namely to the README
authored
34 class Food < ActiveRecord::Base
35 include RocketPants::Cacheable
36 end
37 ```
38
39 ```ruby
40 class FoodsController < RocketPants::Base
41
42 version 1
43
44 # The list of foods is paginated for 5 minutes, the food itself is cached
45 # until it's modified (using Efficient Validation)
46 caches :index, :show, :caches_for => 5.minutes
22b6142 @Sutto More readme tweaks.
authored
47
48 def index
7a362ce @Sutto More tweaks! Namely to the README
authored
49 expose Food.paginate(:page => params[:page])
22b6142 @Sutto More readme tweaks.
authored
50 end
51
52 def show
7a362ce @Sutto More tweaks! Namely to the README
authored
53 expose Food.find(params[:id])
22b6142 @Sutto More readme tweaks.
authored
54 end
55
56 end
57 ```
58
59 And in the router we'd just use the normal REST-like routes in Rails:
60
61 ```ruby
7a362ce @Sutto More tweaks! Namely to the README
authored
62 api :version => 1 do
63 resources :foods, :only => [:index, :show]
64 end
65 ```
66
d6092e9 @Sutto We need the version in the URL
authored
67 And then, using this example, hitting `GET http://localhost:3000/1/foods` would result in:
7a362ce @Sutto More tweaks! Namely to the README
authored
68
69 ```json
70 {
71 "response": [{
72 "id": 1,
73 "name": "Delicious Food"
74 }, {
75 "id": 2,
76 "name": "More Delicious Food"
77 }],
78 "count": 2,
79 "pagination": {
80 "previous": nil,
81 "next": nil,
82 "current": 1,
83 "per_page": 10,
84 "count": 2,
85 "pages": 1
86 }
87 }
22b6142 @Sutto More readme tweaks.
authored
88 ```
89
d6092e9 @Sutto We need the version in the URL
authored
90 with the `Cache-Control` header set whilst hitting `GET http://localhost:3000/1/foods/1` would return:
7a362ce @Sutto More tweaks! Namely to the README
authored
91
92 ```json
93 {
94 "response": {
95 "id": 1,
96 "name": "Delicious Food"
97 }
98 }
99 ```
100
101 with the `Etag` header set.
102
aa5dc16 @Sutto Add JSONP notes
authored
103 #### JSONP
104
105 If you want to enable JSONP support, it's as simple as calling `jsonp` in your class method:
106
107 ```ruby
108 class MyController < RocketPants::Base
109 jsonp
110 end
111 ```
112
113 By default this will use the `callback` parameter, e.g. `GET /1/my?callback=console.log`.
114 To change this parameter, specify the `parameter` option like so:
115
116 ```ruby
117 class MyController < RocketPants::Base
118 jsonp :parameter => :jsonp
119 end
120 ```
121
122 Finally, to disable it in a subclass, simple call `jsonp` in the child and pass `:enable => false` as an option.
123
6c3caed @Sutto Initial link documentation
authored
124 #### Header Metadata
125
126 When `RocketPants.header_metadata` or `config.rocket_pants.header_metadata` are set to true, RocketPants can automatically
127 expose metadata via `X-Api-` headers. Likewise, for paginated responses, if you implement `page_url(page_number)` in your controller
128 with header metadata enabled, RocketPants will automatically add HTTP Link Headers for the next, prev, first and last to your
129 response.
130
131 Likewise, you can manually add link headers using the `link(rel, href, attributes = {})` method like so:
132
133 ```ruby
134 def index
135 # Not an actual rel, just an example...
136 link :profile, user_profile_path(current_user)
137 expose current_user
138 end
139 ```
140
141 For batch adding links, you can use the `links` method:
142
143 ```ruby
144 def index
145 # Probably not the best example...
146 links :next => random_wallpaper_path, :prev => random_wallpaper_path
147 expose Wallpaper.random
148 end
149 ```
150
0222651 @Sutto Add client examples
authored
151 ### Example Client Code
152
153 Using the example above, we could then use the following to write a client:
154
155 ```ruby
156 class FoodsClient < RocketPants::Client
1f6ab56 @Sutto Update version to 1.5.3, update the readme and the changelog
authored
157
0222651 @Sutto Add client examples
authored
158 version 1
159 base_uri 'http://localhost:3000'
160
161 class Food < APISmith::Smash
162 property :id
163 property :name
164 end
165
166 def foods
167 get 'foods', :transformer => Food
168 end
169
170 def food(id)
171 get "foods/#{id}", :transformer => Food
172 end
173
174 end
175 ```
176
98d2351 @Sutto README work and License tweaks
authored
177 ## General Structure
178
179 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.
180
181 Out of the box, we use the following ActionController components:
182
183 * `ActionController::HideActions` - Lets you hide methods from actions.
184 * `ActionController::UrlFor` - `url_for` helpers / tweaks by Rails to make integration with routes work better.
185 * `ActionController::Redirecting` - Allows you to use `redirect_to`.
186 * `ActionController::ConditionalGet` - Adds support for Rails caching controls, e.g. `fresh_when` and `expires_in`.
187 * `ActionController::RackDelegation` - Lets you reset the session and set the response body.
188 * `ActionController::RecordIdentifier` - Gives `dom_class` and `dom_id` methods, used for polymorphic routing.
9858dfb @Sutto Readme updates
authored
189 * `ActionController::HttpAuthentication` Mixins - Gives Token, Digest and Basic authentication.
98d2351 @Sutto README work and License tweaks
authored
190 * `AbstractController::Callbacks` - Adds support for callbacks / filters.
191 * `ActionController::Rescue` - Lets you use `rescue_from`.
192
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
193 And added our own:
98d2351 @Sutto README work and License tweaks
authored
194
195 * `RocketPants::UrlFor` - Automatically includes the current version when generating URLs from the controller.
196 * `RocketPants::Respondable` - The core of RocketPants, the code that handles converting objects to the different container types.
197 * `RocketPants::Versioning` - Allows versioning requirements on the controller to ensure it is only callable with a specific api version.
198 * `RocketPants::Instrumentation` - Adds Instrumentation notifications making it easy to use and hook into with Rails.
199 * `RocketPants::Caching` - Implements time-based caching for index actions and etag-based efficient validation for singular resources.
200 * `RocketPants::ErrorHandling` - Short hand to create errors as well as simplifications to catch and render a standardised error representation.
201 * `RocketPants::Rescuable` - Allows you to hook in to rescuing exceptions and to make it easy to post notifications to tools such as AirBrake.
202
203 To use RocketPants, instead of inheriting from `ActionController::Base`, just inherit from `RocketPants::Base`.
204
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
205 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
206
149db46 @Sutto More README docs / tweaks
authored
207 ## Installing RocketPants
208
209 Installing RocketPants is a simple matter of adding:
210
211 gem 'rocket_pants', '~> 1.0'
212
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
213 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
214
215 ## Configuration
216
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
217 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
218
219 - `config.rocket_pants.use_caching` - Defaulting to true for production environments and false elsewhere, defines whether RocketPants caching setup as described below is used.
1862b03 @Sutto Bump version, add fixes for Moneta 0.7 series
authored
220 - `config.rocket_pants.cache` - A `Moneta::Store` / Moneta adapter instance (depending on the version of Moneta in use)used as the RocketPants cache, defaulting to a memory-based. Change for proper caching. (See [here](https://github.com/minad/moneta) for more information on Moneta.)
6b2a363 @Sutto Update the readme with configuration documentation
authored
221 - `config.rocket_pants.header_metadata` - Defaults to false, if true enables header metadata in the application.
222 - `config.rocket_pants.pass_through_errors` - Defaults true in development and test, false otherwise. If true, will pass through errors up the stack otherwise will swallow them and return a system error via JSON for any unhandled exceptions.
149db46 @Sutto More README docs / tweaks
authored
223
224 ## Version Controllers / Routes
225
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
226 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
227
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
228 ```ruby
229 class UsersController < RocketPants::Base
230 version 1 # A single version
231 # or...
232 version 2..3 # 2-3 support this controller
233 end
234 ```
149db46 @Sutto More README docs / tweaks
authored
235
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
236 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
237
238 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:
239
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
240 ```ruby
241 api :version => 1 do
242 get 'x', :to => 'test#item'
243 end
244 ```
149db46 @Sutto More README docs / tweaks
authored
245
246 Which will route `GET /1/x` to `TestController#item`.
247
248 Likewise, you can specify a route for multiple versions by:
249
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
250 ```ruby
251 api :versions => 1..3 do
252 get 'x', :to => 'test#item'
253 end
254 ```
149db46 @Sutto More README docs / tweaks
authored
255
98d2351 @Sutto README work and License tweaks
authored
256 ## Working with data
257
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
258 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
259
260 - `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).
261 - `paginated` - Render an object as a paginated collection of data.
262 - `collection` - Renders a collection of objects - e.g. an array of users.
263 - `resource` - Renders a single object.
264
265 Along side the above that wrap data, it also provides:
266
267 - `responds` - Renders JSON, normalizing the object first (unwrapped).
268 - `render_json` - Renders an object as JSON.
269
270 ### Singular Resources
271
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
272 Singular resources will be converted to JSON via `serializable_hash`, passing through any objects
3f8d609 @Sutto More type conversion docs
authored
273 and then wrapped in an object as the `response` key:
274
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
275 ```json
276 {
277 "response": {
278 "your": "serialized-object"
279 }
280 }
281 ```
3f8d609 @Sutto More type conversion docs
authored
282
283 ### Collections
284
285 Similar to singular resources, but also include extra data about the count of items.
286
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
287 ```json
288 {
289 "response": [{
290 "name": "object-one"
291 }, {
292 "name": "object-two"
293 }],
294 "count": 2
295 }
296 ```
3f8d609 @Sutto More type conversion docs
authored
297
298 ### Paginated Collections
299
c741f37 @paxer typo fix
paxer authored
300 The final type, similar to collection objects but it includes details about the paginated data:
3f8d609 @Sutto More type conversion docs
authored
301
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
302 ```json
303 {
304 "response": [
305 {"name": "object-one"},
306 {"name": "object-two"},
307 {"name": "object-three"},
308 {"name": "object-four"},
309 {"name": "object-five"}
310 ],
311 "count": 5,
312 "pagination": {
313 "previous": 1,
314 "next": 3,
315 "current": 2,
316 "per_page": 5,
1e498dc @levibuzolic Missing comma in paginated collections example
levibuzolic authored
317 "count": 23,
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
318 "pages": 5
319 }
320 }
321 ```
98d2351 @Sutto README work and License tweaks
authored
322
323 ## Registering / Dealing with Errors
324
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
325 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
326
a270612 @Sutto Add ActiveRecord integration and specs, docs!
authored
327 This comes in useful when you wish to automatically convert exceptions such as `ActiveRecord::RecordNotFound` (Note: This case is handled already) 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
328
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
329 ```json
330 {
331 "error": "standard_error_name",
332 "error_description": "A translated error message describing what happened."
333 }
334 ```
4da07ec @Sutto Started writing docs on the error handling
authored
335
336 It also adds a facilities to make it easy to add extra information to the response.
337
338 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:
339
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
340 ```ruby
341 error! :not_found
342 ```
4da07ec @Sutto Started writing docs on the error handling
authored
343
344 In the controller.
345
b62fc6e @Sutto Add in forbidden, update the error docs
authored
346 Out of the box, the following exceptions come pre-registered and setup. For each of them, you can either use the error form (`error! :error_key) or you can raise an instance of the exception class like normal.
347
348 Note that inside your application, you can also use `rake rocket_pants:errors` to view
349 a list of *all* registered errors, including custom ones.
350
351 <table>
352 <tr>
353 <th>Error Key</th>
354 <th>Exception Class</th>
355 <th>HTTP Status</th>
356 <th>Description</th>
357 </tr>
358 <tr>
359 <td><code>:throttled</code></td>
360 <td><code>RocketPants::Throttled</code></td>
361 <td><code>503 Unavailable</code></td>
362 <td>The user has hit an api throttled error.</td>
363 </tr>
364 <tr>
365 <td><code>:unauthenticated</code></td>
366 <td><code>RocketPants::Unauthenticated</code></td>
367 <td><code>401 Unauthorized</code></td>
368 <td>The user doesn't have valid authentication details.</td>
369 </tr>
370 <tr>
371 <td><code>:invalid_version</code></td>
372 <td><code>RocketPants::Invalidversion</code></td>
373 <td><code>404 Not Found</code></td>
374 <td>An invalid API version was specified.</td>
375 </tr>
376 <tr>
377 <td><code>:not_implemented</code></td>
378 <td><code>RocketPants::NotImplemented</code></td>
379 <td><code>503 Unavailable</code></td>
380 <td>The specified endpoint is not yet implemented.</td>
381 </tr>
382 <tr>
383 <td><code>:not_found</code></td>
384 <td><code>RocketPants::NotFound</code></td>
385 <td><code>404 Not Found</code></td>
386 <td>The given resource could not be found.</td>
387 </tr>
388 <tr>
389 <td><code>:invalid_resource</code></td>
390 <td><code>RocketPants::InvalidResource</code></td>
391 <td><code>422 Unprocessable Entity</code></td>
392 <td>The given resource was invalid.</td>
393 </tr>
394 <tr>
395 <td><code>:bad_request</code></td>
396 <td><code>RocketPants::BadRequest</code></td>
397 <td><code>400 Bad Request</code></td>
398 <td>The given request was not as expected.</td>
399 </tr>
400 <tr>
401 <td><code>:conflict</code></td>
402 <td><code>RocketPants::Conflict</code></td>
403 <td><code>409 Conflict</code></td>
404 <td>The resource was a conflict with the existing version.</td>
405 </tr>
406 <tr>
407 <td><code>:forbidden</code></td>
408 <td><code>RocketPants::Forbidden</code></td>
409 <td><code>403 Forbidden</code></td>
410 <td>The requested action was forbidden.</td>
411 </tr>
412 </table>
4da07ec @Sutto Started writing docs on the error handling
authored
413
6d970f0 @Sutto Add error context extras to the README
authored
414 Note that error also excepts a Hash of contextual options, many which will be passed through to the Rails I18N subsystem. E.g:
415
416 ```ruby
417 error! :throttled, :max_per_hour => 100
418 ```
419
420 Will look up the translation `rocket_pants.errors.throttled` in your I18N files, and call them with `:max_per_hour` as an argument.
421
422 Finally, You can use this to also pass custom values to include in the response, e.g:
423
424 ```ruby
e74a34a @Sutto Use :metadata over extras
authored
425 error! :throttled, :metadata => {:code => 123}
6d970f0 @Sutto Add error context extras to the README
authored
426 ```
427
428 Will return something similar to:
429
430 ```json
431 {
432 "error": "throttled",
433 "error_description": "The example error message goes here",
434 "code": 123
435 }
436 ```
437
bf65cf1 @Sutto Update the docs
authored
438 ### Built in ActiveRecord Errors
a270612 @Sutto Add ActiveRecord integration and specs, docs!
authored
439
440 Out of the box, Rocket Pants will automatically map the following to built in errors and rescue them
441 as appropriate.
442
443 - `ActiveRecord::RecordNotFound` into `RocketPants::NotFound`
4224a6c @Sutto Update README.md for RecordNotUnique, Cheers @fredwu
authored
444 - `ActiveRecord::RecordNotUnique` into `RocketPants::Conflict`
a270612 @Sutto Add ActiveRecord integration and specs, docs!
authored
445 - `ActiveRecord::RecordNotSaved` into `RocketPants::InvalidResource (with no validation messages).`
446 - `ActiveRecord::RecordInvalid` into `RocketPants::InvalidResource (with messages in the "messages" key of the JSON).`
447
c755665 @Sutto Note about automatic rescue
authored
448 **Please Note:** The default RecordInvalid mapper can potentially leak information about your structure - If there is data
449 in the default error messages you don't wish to expose, we suggest implementing it on a per-action basis (using normal
450 rescues / `.save` instead of `.save!`) OR remapping the handler for `ActiveRecord::RecordInvalid`.
451
a270612 @Sutto Add ActiveRecord integration and specs, docs!
authored
452 For Invalid Resource messages, the response looks roughly akin to:
453
9d28bed @Sutto Add in more docs
authored
454 ```json
455 {
456 "error": "invalid_resource",
457 "error_description": "The current resource was deemed invalid.",
458 "messages": {
459 "name": ["can't be blank"],
460 "child_number":["can't be blank", "is not a number"],
461 "latin_name": ["is too short (minimum is 5 characters)", "is invalid"]
462 }
463 }
464 ```
a270612 @Sutto Add ActiveRecord integration and specs, docs!
authored
465
a79e437 @Sutto README updates
authored
466 ### A Note on Mongoid
467
468 We currently don't support mongoid / other ORMs in RocketPants, but you can map errors directly like so:
469
470 ```ruby
471 ApiController < RocketPants::Base
472 map_error! Mongoid::Errors::Validations do |exception|
473 RocketPants::InvalidResource.new exception.record.errors
474 end
475 end
476 ```
477
478 Thanks to @tiredenzo on #47 for this information. If you'd be interested in making
479 a `rocket_pants-mongoid` gem mapping more errors, please get in touch.
480
98d2351 @Sutto README work and License tweaks
authored
481 ## Implementing Efficient Validation
482
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
483 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
484
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
485 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
486
487 For example, you'd add the following to your model:
488
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
489 ```ruby
490 class User < ActiveRecord::Base
491 include RocketPants::Cacheable
492 end
493 ```
149db46 @Sutto More README docs / tweaks
authored
494
495 And then in your controller, you'd have something like:
496
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
497 ```ruby
498 class UsersController < RocketPants::Base
149db46 @Sutto More README docs / tweaks
authored
499
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
500 version 1
149db46 @Sutto More README docs / tweaks
authored
501
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
502 # Time based, e.g. collections, will be cached for 5 minutes - whilst singular
503 # items e.g. show will use etag-based caching:
504 caches :show, :index, :caches_for => 5.minutes
149db46 @Sutto More README docs / tweaks
authored
505
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
506 def index
507 expose User.all
508 end
149db46 @Sutto More README docs / tweaks
authored
509
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
510 def show
511 expose User.find(params[:id])
512 end
149db46 @Sutto More README docs / tweaks
authored
513
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
514 end
515 ```
149db46 @Sutto More README docs / tweaks
authored
516
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
517 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
518
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
519 ## Using with RSpec
73b2f4e Add misc. test helpers
Darcy Laycock authored
520
f0a3bbd @Sutto Update README.md to mention needing the version parameters in specs. …
authored
521 When testing controllers written using RocketPants, your normal rails approach should work.
522 The only difference one needs to take into the account is the need to specify the `:version`
523 parameter on any http requests, e.g:
524
525 ```ruby
1b57550 @xunker updated readme to include info on rspec post and the default_version …
xunker authored
526 # get
f0a3bbd @Sutto Update README.md to mention needing the version parameters in specs. …
authored
527 get :index, :version => 1
1b57550 @xunker updated readme to include info on rspec post and the default_version …
xunker authored
528
529 # post
530 post :index, :version => 1, :payload => { :foo => 'bar' ... }
f0a3bbd @Sutto Update README.md to mention needing the version parameters in specs. …
authored
531 ```
532
533 Otherwise it will raise an exception.
534
1b57550 @xunker updated readme to include info on rspec post and the default_version …
xunker authored
535 To set the version to be used for all tests in a given set of specs you can use the `default_version` tag. It will set the version for all tests in that block and not require `:version` to be set individually:
536
537 ```ruby
538 describe YourAwesomeController do
539 default_version 1
540 end
541 ```
542
1f6ab56 @Sutto Update version to 1.5.3, update the readme and the changelog
authored
543 RocketPants includes a set of helpers to make testing controllers built on `RocketPants::Base` simpler.
98d2351 @Sutto README work and License tweaks
authored
544
945643f @johnrees README be_singular_resource typo fix
johnrees authored
545 * `be_singular_resource` - Checks the response is a single resource - e.g. `response.should be_singular_resource`.
19b8bc5 @Sutto RSpec integration docs
authored
546 * `be_collection_resource` - Checks the response is collection of resources - e.g. `response.should be_collection_resource`.
e7f4299 @Sutto Finish implementing jsonp, add a stubbed out helper_method implementa…
authored
547 * `be_paginated_resource` - Checks the response is paginated - e.g. `response.should be_paginated_resource`.
19b8bc5 @Sutto RSpec integration docs
authored
548 * `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`.
549 * `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`
550
551 Likewise, it adds the following helper methods:
552
553 - `parsed_body` - A parsed-JSON representation of the response.
554 - `decoded_body` - A `Hashie::Mash` of the response body.
555
556 To set up the integration, in your `spec/spec_helper.rb` add:
557
45ed4af @fredwu Fixed some small typos and enhanced syntax highlighting in the README
fredwu authored
558 ```ruby
559 config.include RocketPants::TestHelper, :type => :controller
560 config.include RocketPants::RSpecMatchers, :type => :controller
561 ```
19b8bc5 @Sutto RSpec integration docs
authored
562
563 Inside the `RSpec.configure do |config|` block.
98d2351 @Sutto README work and License tweaks
authored
564
8ced3cb @Sutto Update README.md
authored
565 ## Contributors
566
567 - [Darcy Laycock](https://github.com/Sutto) - Main developer, current maintainer.
568 - [Steve Webb](https://github.com/swebb) - Helped with original work at [The Frontier Group](https://github.com/thefrontiergroup), inc. original design.
1f6ab56 @Sutto Update version to 1.5.3, update the readme and the changelog
authored
569 - [Fred Wu](https://github.com/fredwu) - README fixes, other contributions / fixes.
8ced3cb @Sutto Update README.md
authored
570 - [Levi Buzolic](https://github.com/levibuzolic) - README fixes.
1f6ab56 @Sutto Update version to 1.5.3, update the readme and the changelog
authored
571 - [Samuel Cochran](https://github.com/sj26) - Misc. work on RocketPants / tweaks.
a79e437 @Sutto README updates
authored
572 - [tiredenzo](https://github.com/tiredenzo) - mongoid error information.
573 - [Fabio Napoleoni](https://github.com/fabn) - Version prefix support.
574 - [Justin Jones](https://github.com/nagash) - Bug fixes.
575 - [Eran Kampf](https://github.com/ekampf) - Support for `:bad_request` errors.
576 - [Matthew Nielsen](https://github.com/xunker) - README fixes.
577 - [Pavel Kotlyar](https://github.com/paxer) - Typo fixes.
578 - [John Rees](https://github.com/johnrees) - README fixes.
5ddb91e @keithpitt Update README.md
keithpitt authored
579 - [Keith Pitt](https://github.com/keithpitt) - Bug fixes.
24e9690 @Sutto Add @oakho to the contributors.
authored
580 - [Antoine Lagadec](https://github.com/oakho) - Bug fixes.
8ced3cb @Sutto Update README.md
authored
581
b86d1c8 @Sutto Add in note about missing contributors
authored
582 If you're not on this list and thing you should be, let @Sutto know.
583
98d2351 @Sutto README work and License tweaks
authored
584 ## Contributing
585
586 We encourage all community contributions. Keeping this in mind, please follow these general guidelines when contributing:
587
588 * Fork the project
589 * Create a topic branch for what you’re working on (git checkout -b awesome_feature)
590 * Commit away, push that up (git push your\_remote awesome\_feature)
591 * Create a new GitHub Issue with the commit, asking for review. Alternatively, send a pull request with details of what you added.
592 * 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.
593
5295431 @Sutto Reflect new contribution guide.
authored
594 Other than that, our guidelines very closely match the GemCutter guidelines [here](https://github.com/rubygems/rubygems.org/wiki/Contribution-Guidelines).
98d2351 @Sutto README work and License tweaks
authored
595
596 (Thanks to [GemCutter](http://wiki.github.com/qrush/gemcutter/) for the contribution guide)
73b2f4e Add misc. test helpers
Darcy Laycock authored
597
98d2351 @Sutto README work and License tweaks
authored
598 ## License
73b2f4e Add misc. test helpers
Darcy Laycock authored
599
22b6142 @Sutto More readme tweaks.
authored
600 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.