{"id":13463408,"url":"https://github.com/Sutto/rocket_pants","last_synced_at":"2025-03-25T06:31:59.494Z","repository":{"id":2643900,"uuid":"3633434","full_name":"Sutto/rocket_pants","owner":"Sutto","description":"API building tools on top of ActionController. Also, an awesome name.","archived":false,"fork":false,"pushed_at":"2019-04-26T16:14:25.000Z","size":1050,"stargazers_count":980,"open_issues_count":36,"forks_count":130,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-03-02T08:50:45.130Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Sutto.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-03-06T01:30:38.000Z","updated_at":"2025-02-10T09:36:34.000Z","dependencies_parsed_at":"2022-08-06T12:30:51.590Z","dependency_job_id":null,"html_url":"https://github.com/Sutto/rocket_pants","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sutto%2Frocket_pants","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sutto%2Frocket_pants/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sutto%2Frocket_pants/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Sutto%2Frocket_pants/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Sutto","download_url":"https://codeload.github.com/Sutto/rocket_pants/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245414344,"owners_count":20611357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T13:00:52.966Z","updated_at":"2025-03-25T06:31:59.173Z","avatar_url":"https://github.com/Sutto.png","language":"Ruby","readme":"# Rocket Pants! [![Build Status](https://secure.travis-ci.org/Sutto/rocket_pants.png?branch=master)](http://travis-ci.org/Sutto/rocket_pants)\n\n**Please Note:** Work on RocketPants 2.0 is currently underway on the [2.0-rewrite](https://github.com/Sutto/rocket_pants/tree/2.0-rewrite) branch. Please check there before requesting features.\n\n## Introduction\n\nFirst 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.\n\nAt 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.\n\n## Key Features\n\nWhy use RocketPants over alternatives like Grape or normal Rails? The reasons we built it come down to a couple of simple things:\n\n1. **[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.\n2. **[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.\n3. **[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](#tracking-errors-w-airbrake-honeybadger-or-bugsnag) and do things such as including an error identifier in the response.\n4. **[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. If you're using Strong Parameters (e.g. in Rails 4), we'll even give you support for that.\n5. **[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.\n6. **[Simple tools to consume RocketPants apis](#example-client-code)** - RocketPants includes the `RocketPants::Client` class which builds upon [APISmith](https://github.com/Sutto/api_smith) to make it easier to build clients e.g. automatically converting paginated responses back.\n7. **[Built-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.\n8. **[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.\n9. **[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 (or `:each_serializer`) and we'll automatically take care of invoking it for you.\n\n## Examples\n\n### A full example application\n\nLearn 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.\n\n### Example Server Code\n\nSay, for example, you have a basic Food model:\n\n```ruby\nclass Food \u003c ActiveRecord::Base\n  include RocketPants::Cacheable\nend\n```\n\n```ruby\nclass FoodsController \u003c RocketPants::Base\n\n  version 1\n\n  # The list of foods is cached for 5 minutes, the food itself is cached\n  # until it's modified (using Efficient Validation)\n  caches :index, :show, :cache_for =\u003e 5.minutes\n\n  def index\n    expose Food.paginate(:page =\u003e params[:page])\n  end\n\n  def show\n    expose Food.find(params[:id])\n  end\n\nend\n```\n\nAnd in the router we'd just use the normal REST-like routes in Rails:\n\n```ruby\napi :version =\u003e 1 do\n  resources :foods, :only =\u003e [:index, :show]\nend\n```\n\nAnd then, using this example, hitting `GET http://localhost:3000/1/foods` would result in:\n\n```json\n{\n  \"response\": [{\n    \"id\":    1,\n    \"name\": \"Delicious Food\"\n  }, {\n    \"id\":   2,\n    \"name\": \"More Delicious Food\"\n  }],\n  \"count\": 2,\n  \"pagination\": {\n    \"previous\": null,\n    \"next\":     null,\n    \"current\":  1,\n    \"per_page\": 10,\n    \"count\":    2,\n    \"pages\":    1\n  }\n}\n```\n\nwith the `Cache-Control` header set whilst hitting `GET http://localhost:3000/1/foods/1` would return:\n\n```json\n{\n  \"response\": {\n    \"id\":    1,\n    \"name\": \"Delicious Food\"\n  }\n}\n```\n\nwith the `Etag` header set.\n\n#### JSONP\n\nIf you want to enable JSONP support, it's as simple as calling `jsonp` in your class method:\n\n```ruby\nclass MyController \u003c RocketPants::Base\n  jsonp\nend\n```\n\nBy default this will use the `callback` parameter, e.g. `GET /1/my?callback=console.log`.\nTo change this parameter, specify the `parameter` option like so:\n\n```ruby\nclass MyController \u003c RocketPants::Base\n  jsonp :parameter =\u003e :jsonp\nend\n```\n\nFinally, to disable it in a subclass, simple call `jsonp` in the child and pass `:enable =\u003e false` as an option.\n\n#### Header Metadata\n\nWhen `RocketPants.header_metadata` or `config.rocket_pants.header_metadata` are set to true, RocketPants can automatically\nexpose metadata via `X-Api-` headers. Likewise, for paginated responses, if you implement `page_url(page_number)` in your controller\nwith header metadata enabled, RocketPants will automatically add HTTP Link Headers for the next, prev, first and last to your\nresponse.\n\nLikewise, you can manually add link headers using the `link(rel, href, attributes = {})` method like so:\n\n```ruby\ndef index\n  # Not an actual rel, just an example...\n  link :profile, user_profile_path(current_user)\n  expose current_user\nend\n```\n\nFor batch adding links, you can use the `links` method:\n\n```ruby\ndef index\n  # Probably not the best example...\n  links :next =\u003e random_wallpaper_path, :prev =\u003e random_wallpaper_path\n  expose Wallpaper.random\nend\n```\n\n### Example Client Code\n\nUsing the example above, we could then use the following to write a client:\n\n```ruby\nclass FoodsClient \u003c RocketPants::Client\n\n  version  1\n  base_uri 'http://localhost:3000'\n\n  class Food \u003c APISmith::Smash\n    property :id\n    property :name\n  end\n\n  def foods\n    get 'foods', :transformer =\u003e Food\n  end\n\n  def food(id)\n    get \"foods/#{id}\", :transformer =\u003e Food\n  end\n\nend\n```\n\n## General Structure\n\nRocketPants 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.\n\nOut of the box, we use the following ActionController components:\n\n* `ActionController::HideActions` - Lets you hide methods from actions.\n* `ActionController::UrlFor` - `url_for` helpers / tweaks by Rails to make integration with routes work better.\n* `ActionController::Redirecting` - Allows you to use `redirect_to`.\n* `ActionController::ConditionalGet` - Adds support for Rails caching controls, e.g. `fresh_when` and `expires_in`.\n* `ActionController::RackDelegation` - Lets you reset the session and set the response body.\n* `ActionController::RecordIdentifier` - Gives `dom_class` and `dom_id` methods, used for polymorphic routing.\n* `ActionController::HttpAuthentication` Mixins - Gives Token, Digest and Basic authentication.\n* `AbstractController::Callbacks` - Adds support for callbacks / filters.\n* `ActionController::Rescue` - Lets you use `rescue_from`.\n\nAnd added our own:\n\n* `RocketPants::UrlFor` - Automatically includes the current version when generating URLs from the controller.\n* `RocketPants::Respondable` - The core of RocketPants, the code that handles converting objects to the different container types.\n* `RocketPants::Versioning` - Allows versioning requirements on the controller to ensure it is only callable with a specific api version.\n* `RocketPants::Instrumentation` - Adds Instrumentation notifications making it easy to use and hook into with Rails.\n* `RocketPants::Caching` - Implements time-based caching for index actions and etag-based efficient validation for singular resources.\n* `RocketPants::ErrorHandling` - Short hand to create errors as well as simplifications to catch and render a standardised error representation.\n* `RocketPants::Rescuable` - Allows you to hook in to rescuing exceptions and to make it easy to [post notifications to tools such as Airbrake](#tracking-errors-w-airbrake-honeybadger-or-bugsnag).\n* `RocketPants::StrongParameters` - Adds support for strong parameters.\n\nTo use RocketPants, instead of inheriting from `ActionController::Base`, just inherit from `RocketPants::Base`.\n\nLikewise, in Rails applications RocketPants also adds `RocketPants::CacheMiddleware` before the controller endpoints to implement [\"Efficient Validation\"](http://rtomayko.github.com/rack-cache/faq).\n\n## Installing RocketPants\n\nInstalling RocketPants is a simple matter of adding:\n\n    gem 'rocket_pants', '~\u003e 1.0'\n\nTo your `Gemfile` and running `bundle install`. Next, instead of inheriting from `ActionController::Base`, simply inherit from `RocketPants::Base`. For example, if you're working with an API-only application, instead of having this at the top of `application_controller.rb`:\n\n    class ApplicationController \u003c ActionController::Base\n\nyou would do this:\n\n    class ApplicationController \u003c RocketPants::Base\n\nYour other controllers would inherit from `ApplicationController` as usual. For example:\n\n    class UsersController \u003c ApplicationController\n\nOtherwise, you can generate a new `api_controller.rb` base controller which inherits from `RocketPants::Base`, and place all your logic there. For example:\n\nIn `application_controller.rb`:\n\n    class ApplicationController \u003c ActionController::Base\n\nIn `api_controller.rb`:\n\n```\nclass ApiController \u003c RocketPants::Base\n\n# logic goes here\n```\n\nIn your other controllers, such as `users_controller.rb`:\n\n    class UsersController \u003c ApiController\n\n\n## Configuration\n\nSetting 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):\n\n- `config.rocket_pants.use_caching` - Defaulting to true for production environments and false elsewhere, defines whether RocketPants caching setup as described below is used.\n- `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.)\n- `config.rocket_pants.header_metadata` - Defaults to false, if true enables header metadata in the application.\n- `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.\n\n## Version Controllers / Routes\n\nThe 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:\n\n```ruby\nclass UsersController \u003c RocketPants::Base\n  version 1 # A single version\n  # or...\n  version 2..3 # 2-3 support this controller\nend\n```\n\nAnd 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.\n\nNext, 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:\n\n```ruby\napi :version =\u003e 1 do\n  get 'x', :to =\u003e 'test#item'\nend\n```\n\nWhich will route `GET /1/x` to `TestController#item`.\n\nLikewise, you can specify a route for multiple versions by:\n\n```ruby\napi :versions =\u003e 1..3 do\n  get 'x', :to =\u003e 'test#item'\nend\n```\n\n### How do I layout file system versions versions?\n\nUsing users an an example, for a namespaced / modularised version controller the file system location would be\n`app/controllers/api/v1/users_controller.rb` - Rails uses it's own inflection to look for `Api::V1::UsersController` in that file.\nIn here, you'd write your control roughly like:\n\n```ruby\nclass Api::V1::UsersController \u003c RocketPants::Base\n  version 1\n\n  def index\n    expose User.all # Not what we'd actually do, of course.\n  end\n\nend\n```\n\nNote that I'd personally also introduce `Api::V1::BaseController`, and inherit from that - that way any shared logic (e.g. authentication) can be put in there.\n\nFinally, in the routes - the easiest way would be in the api declaration:\n\n```ruby\napi versions: 1, module: \"api/v1\" do\n  resources :users, only: [:index]\nend\n```\n\nWhich will set up `/1/users` to hit the index action of `Api::V1::UsersController` - the `module` parameter comes from the rails built in routing configuration: http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-scope\n\n## Working with data\n\nWhen 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:\n\n- `expose` / `exposes` - The core of all type conversion, will check the type of data and automatically convert it to the correct type (for either a singular, collection or paginated resource).\n- `paginated` - Render an object as a paginated collection of data.\n- `collection` - Renders a collection of objects - e.g. an array of users.\n- `resource` - Renders a single object.\n\nAlong side the above that wrap data, it also provides:\n\n- `responds` - Renders JSON, normalizing the object first (unwrapped).\n- `render_json` - Renders an object as JSON.\n\n### Singular Resources\n\nSingular resources will be converted to JSON via `serializable_hash`, passing through any objects\nand then wrapped in an object as the `response` key:\n\n```json\n{\n  \"response\": {\n    \"your\": \"serialized-object\"\n  }\n}\n```\n\n### Collections\n\nSimilar to singular resources, but also include extra data about the count of items.\n\n```json\n{\n  \"response\": [{\n    \"name\": \"object-one\"\n  }, {\n    \"name\": \"object-two\"\n  }],\n  \"count\": 2\n}\n```\n\n### Paginated Collections\n\nThe final type, similar to collection objects but it includes details about the paginated data:\n\n```json\n{\n  \"response\": [\n    {\"name\": \"object-one\"},\n    {\"name\": \"object-two\"},\n    {\"name\": \"object-three\"},\n    {\"name\": \"object-four\"},\n    {\"name\": \"object-five\"}\n  ],\n  \"count\": 5,\n  \"pagination\": {\n    \"previous\": 1,\n    \"next\":     3,\n    \"current\":  2,\n    \"per_page\": 5,\n    \"count\":    23,\n    \"pages\":    5\n  }\n}\n```\n\n## Registering / Dealing with Errors\n\nOne 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.\n\nThis 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:\n\n```json\n{\n  \"error\":             \"standard_error_name\",\n  \"error_description\": \"A translated error message describing what happened.\"\n}\n```\n\nIt also adds a facilities to make it easy to add extra information to the response.\n\nRocketPants will also attempt to convert all errors in the controller, defaulting to `\"system\"` as the exception name and message as the error description. We also provide a registry to allow throwing exception from their symbolic name like so:\n\n```ruby\nerror! :not_found\n```\n\nIn the controller.\n\nOut 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.\n\nNote that inside your application, you can also use `rake rocket_pants:errors` to view\na list of *all* registered errors, including custom ones.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eError Key\u003c/th\u003e\n    \u003cth\u003eException Class\u003c/th\u003e\n    \u003cth\u003eHTTP Status\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:throttled\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::Throttled\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e503 Unavailable\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe user has hit an api throttled error.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:unauthenticated\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::Unauthenticated\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e401 Unauthorized\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe user doesn't have valid authentication details.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:invalid_version\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::Invalidversion\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e404 Not Found\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eAn invalid API version was specified.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:not_implemented\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::NotImplemented\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e503 Unavailable\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe specified endpoint is not yet implemented.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:not_found\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::NotFound\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e404 Not Found\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe given resource could not be found.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:invalid_resource\u003c/code\u003e*\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::InvalidResource\u003c/code\u003e*\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e422 Unprocessable Entity\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe given resource was invalid.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:bad_request\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::BadRequest\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e400 Bad Request\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe given request was not as expected.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:conflict\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::Conflict\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e409 Conflict\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe resource was a conflict with the existing version.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e:forbidden\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eRocketPants::Forbidden\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e403 Forbidden\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe requested action was forbidden.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nNote that error also excepts a Hash of contextual options, many which will be passed through to the Rails I18N subsystem. E.g:\n\n```ruby\nerror! :throttled, :max_per_hour =\u003e 100\n```\n\nWill look up the translation `rocket_pants.errors.throttled` in your I18N files, and call them with `:max_per_hour` as an argument.\n\nFinally, You can use this to also pass custom values to include in the response, e.g:\n\n```ruby\nerror! :throttled, :metadata =\u003e {:code =\u003e 123}\n```\n\nWill return something similar to:\n\n```json\n{\n  \"error\":             \"throttled\",\n  \"error_description\": \"The example error message goes here\",\n  \"code\":              123\n}\n```\n\n\\* Note that `:invalid_resource` (`RocketPants::InvalidResource`), although registered as a default RocketPants error, does not behave like other default registered errors. When using it, you **must** include an ActiveModel errors object, e.g.:\n\n```ruby\nerror!(:invalid_resource, post.errors)\n# or\nrender_error RocketPants::InvalidResource.new(post.errors)\n```\n\nIf you don't do that, you may get an `ArgumentError`, because of the way Rocket Pants handles instantiation of a `RocketPants::InvalidResource`.\n\n### Built in ActiveRecord Errors\n\nOut of the box, Rocket Pants will automatically map the following to built in errors and rescue them\nas appropriate.\n\n- `ActiveRecord::RecordNotFound` into `RocketPants::NotFound`\n- `ActiveRecord::RecordNotUnique` into `RocketPants::Conflict`\n- `ActiveRecord::RecordNotSaved` into `RocketPants::InvalidResource (with no validation messages).`\n- `ActiveRecord::RecordInvalid` into `RocketPants::InvalidResource (with messages in the \"messages\" key of the JSON).`\n\n**Please Note:** The default RecordInvalid mapper can potentially leak information about your structure - If there is data\nin the default error messages you don't wish to expose, we suggest implementing it on a per-action basis (using normal\nrescues / `.save` instead of `.save!`) OR remapping the handler for `ActiveRecord::RecordInvalid`.\n\nFor Invalid Resource messages, the response looks roughly akin to:\n\n```json\n{\n  \"error\": \"invalid_resource\",\n  \"error_description\": \"The current resource was deemed invalid.\",\n  \"messages\": {\n    \"name\":        [\"can't be blank\"],\n    \"child_number\":[\"can't be blank\", \"is not a number\"],\n    \"latin_name\":  [\"is too short (minimum is 5 characters)\", \"is invalid\"]\n  }\n}\n```\n\n### A Note on Mongoid\n\nWe currently don't support mongoid / other ORMs in RocketPants, but you can map errors directly like so:\n\n```ruby\nApiController \u003c RocketPants::Base\n  map_error! Mongoid::Errors::Validations do |exception|\n    RocketPants::InvalidResource.new exception.record.errors\n  end\nend\n```\n\nThanks to @tiredenzo on #47 for this information. If you'd be interested in making\na `rocket_pants-mongoid` gem mapping more errors, please get in touch.\n\n### Strong Parameters\n\nOne of the newer features of Rocket Pants, if you have the Strong Parameters plugin on Rails 3\nor are using Rails 4, is that we'll automatically rescue strong parameters errors and render them\nas `bad_request` API errors to the requesting users.\n\n### Tracking errors w/ Airbrake, Honeybadger or Bugsnag\n\nSince Rocket Pants automatically rescues server errors, you'll additionally need to configure tracking them if you want to be warned when they happen.\n\nRocket Pants comes with built in support for [Airbrake](https://airbrake.io/), [Honeybadger](https://www.honeybadger.io/) and [Bugsnag](https://bugsnag.com/). Depending on your prefered tracking solution, in your base controller add this:\n\n```ruby\nclass ApplicationController \u003c RocketPants::Base\n  # Airbrake\n  use_named_exception_notifier :airbrake\n  # or Honeybadger\n  use_named_exception_notifier :honeybadger\n  # or Bugsnag\n  use_named_exception_notifier :bugsnag\nend\n```\n\nIf you're using some other service, you can add a custom notifier:\n\n```ruby\nclass ApplicationController \u003c RocketPants::Base\n  self.exception_notifier_callback = lambda do |controller, exception, request|\n    # track errors\n  end\nend\n```\n\n## Implementing Efficient Validation\n\nOne 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.\n\nTo do this, it uses `RocketPants.cache`, by default any Moneta-based store, to keep a mapping of object -\u003e 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.\n\nFor example, you'd add the following to your model:\n\n```ruby\nclass User \u003c ActiveRecord::Base\n  include RocketPants::Cacheable\nend\n```\n\nAnd then in your controller, you'd have something like:\n\n```ruby\nclass UsersController \u003c RocketPants::Base\n\n  version 1\n\n  # Time based, e.g. collections, will be cached for 5 minutes - whilst singular\n  # items e.g. show will use etag-based caching:\n  caches :show, :index, :cache_for =\u003e 5.minutes\n\n  def index\n    expose User.all\n  end\n\n  def show\n    expose User.find(params[:id])\n  end\n\nend\n```\n\nWhen 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.\n\n## Using with RSpec\n\nWhen testing controllers written using RocketPants, your normal rails approach should work.\nThe only difference one needs to take into the account is the need to specify the `:version`\nparameter on any http requests, e.g:\n\n```ruby\n# get\nget :index, :version =\u003e 1\n\n# post\npost :index, :version =\u003e 1, :payload =\u003e { :foo =\u003e 'bar' ... }\n```\n\nOtherwise it will raise an exception.\n\nTo 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:\n\n```ruby\ndescribe YourAwesomeController do\n  default_version 1\nend\n```\n\nRocketPants includes a set of helpers to make testing controllers built on `RocketPants::Base` simpler.\n\n* `be_singular_resource` - Checks the response is a single resource - e.g. `response.should be_singular_resource`.\n* `be_collection_resource` - Checks the response is collection of resources - e.g. `response.should be_collection_resource`.\n* `be_paginated_resource` - Checks the response is paginated - e.g. `response.should be_paginated_resource`.\n* `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`.\n* `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`\n\nLikewise, it adds the following helper methods:\n\n- `parsed_body` - A parsed-JSON representation of the response.\n- `decoded_body` - A `Hashie::Mash` of the response body.\n\nTo set up the integration, in your `spec/spec_helper.rb` add:\n\n```ruby\nconfig.include RocketPants::TestHelper,    :type =\u003e :controller\nconfig.include RocketPants::RSpecMatchers, :type =\u003e :controller\n```\n\nInside the `RSpec.configure do |config|` block.\n\n## Contributors\n\n- [Darcy Laycock](https://github.com/Sutto) - Main developer, current maintainer.\n- [Steve Webb](https://github.com/swebb) - Helped with original work at [The Frontier Group](https://github.com/thefrontiergroup), inc. original design.\n- [Fred Wu](https://github.com/fredwu) - README fixes, other contributions / fixes.\n- [Levi Buzolic](https://github.com/levibuzolic) - README fixes.\n- [Samuel Cochran](https://github.com/sj26) - Misc. work on RocketPants / tweaks.\n- [tiredenzo](https://github.com/tiredenzo) - mongoid error information.\n- [Fabio Napoleoni](https://github.com/fabn) - Version prefix support.\n- [Justin Jones](https://github.com/nagash) - Bug fixes.\n- [Eran Kampf](https://github.com/ekampf) - Support for `:bad_request` errors.\n- [Matthew Nielsen](https://github.com/xunker) - README fixes.\n- [Pavel Kotlyar](https://github.com/paxer) - Typo fixes.\n- [John Rees](https://github.com/johnrees) - README fixes.\n- [Keith Pitt](https://github.com/keithpitt) - Bug fixes.\n- [Antoine Lagadec](https://github.com/oakho) - Bug fixes.\n- [Moncef Belyamani](https://github.com/monfresh) - README clarification.\n- [Jörg Schiller](https://github.com/joergschiller) - Strong Parameter support, `process` fixes.\n- [Aron Hegyi](https://github.com/ahegyi) - Doc tweaks for `:invalid_resource`.\n- [Manuel Meurer](https://github.com/manuelmeurer) for Doc tweaks.\n- [Travis Pew](https://github.com/travisp) for initial RSpec v3 support.\n- [Brandt Lareau](https://github.com/newdark) for RSpec v3 fixes.\n- [David Pedersen](https://github.com/davidpdrsn) for Rails 4.2 fixes.\n- [Damir Svrtan](https://github.com/DamirSvrtan) for Travis CI fixes.\n- [Michael Chrisco](https://github.com/michaelachrisco) for spelling fixes.\n- [Kevin Jalbert](https://github.com/kevinjalbert) for spelling fixes.\n- [Damir Svrtan](https://github.com/DamirSvrtan) for support for bugsnag, docs and tests.\n\nIf you're not on this list and thing you should be, let @Sutto know.\n\n## Contributing\n\nWe encourage all community contributions. Keeping this in mind, please follow these general guidelines when contributing:\n\n* Fork the project\n* Create a topic branch for what you’re working on (git checkout -b awesome_feature)\n* Commit away, push that up (git push your\\_remote awesome\\_feature)\n* Create a new GitHub Issue with the commit, asking for review. Alternatively, send a pull request with details of what you added.\n* 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.\n\nOther than that, our guidelines very closely match the GemCutter guidelines [here](https://github.com/rubygems/rubygems.org/wiki/Contribution-Guidelines).\n\n(Thanks to [GemCutter](http://wiki.github.com/qrush/gemcutter/) for the contribution guide)\n\n## License\n\nRocketPants is released under the MIT License (see the [license file](https://github.com/Sutto/rocket_pants/blob/master/LICENSE)) and is copyright Filter Squad and Darcy Laycock, 2013.\n","funding_links":[],"categories":["Web Apps, Services \u0026 Interaction","Ruby"],"sub_categories":["API Builders"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSutto%2Frocket_pants","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSutto%2Frocket_pants","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSutto%2Frocket_pants/lists"}