Skip to content
This repository has been archived by the owner on Feb 17, 2023. It is now read-only.

nicolasdespres/respect-rails

Repository files navigation

Respect plugin for Rails

Respect for Rails lets you write the documentation of your REST API using Ruby code. Your app's API is published using a Rails engine so it is always deployed along with your application and stays synchronized. A filter is available so you can also easily validate requests and responses. Thanks to that your incoming parameters will also be sanitized so if you expect a URI in a parameter value you will get a URI object instead of a string object containing a URI. It follows Rails DRY principle and save you a lot of typing since it fetches most of the information automatically by inspecting your routes, their constraints and your model validators. You can always adjust the default by defining the schema per resource and/or controller.

Features

  • A compact DSL from the Respect gem to specify your REST API documentation.
  • Filters to automatically validate and sanitize incoming parameters.
  • A Rails engine to serve your public REST API documentation.

See the RELEASE_NOTES file for detailed feature listing.

Take a tour

This section guides you for a walk around the main features available.

Document an action request

Respect for Rails lets you easily describe the structure of incoming requests and outgoing responses using a simple and compact Ruby DSL. Assuming you have the scaffold of a ContactsController, the structure for its create action may look like this:

# in app/controllers/contacts_controller.rb
# POST /contacts
# POST /contacts.json
def_action_schema :create do |a|
  a.documentation "Create a new contact in the address book."
  a.request do |r|
    r.body_parameters do |s|
      # They look like something like that:
      #   { contact: { name: "Albert", age: 62, homepage: "http://example.org" } }
      s.hash "contact" do |s|
        s.string "name", doc: "The name of the contact."
        s.integer "age", doc: "How old is the contact."
        s.uri "homepage", doc: "The URL of the contact's homepage"
      end
    end
  end
end
def create
  # ...
end

The def_action_schema macro only defines a create_schema method in your controller.

Note that we distinguish from where the parameters come from (path, query or body) for the sake of documentation.

To see the generated doc, you must mount the provided engine like this:

# in config/routes.rb
mount Respect::Rails::Engine => "/rest_spec"

Now if you point your favorite web browser to http://localhost:3000/rest_spec. You should see something like that

Alt Text

Document an action response

When documenting an API it is also important to write how the response will look like. You can add this code to specify the body of the response when the status is "created":

# in app/controllers/contacts_controller.rb
# in def_action_schema :create block
a.response_for do |status|
  status.created do |r|
    r.body do |s|
      s.integer name, greater_than: 0, doc: "The identifier of this contact."
      s.string "name", doc: "The name of the contact."
      s.integer "age", doc: "How old is the contact."
      s.uri "homepage", doc: "The URL of the contact's homepage"
      s.datetime "created_at", doc: "When this record has been created."
      s.datetime "updated_at", doc: "When this record has been updated lastly."
    end
  end
end

The generated documentation would look like that:

Alt Text

The specification standard used to document schema is defined at json-schema.org (we currenly follow draft v3).

Factor specification code

As you have probably noticed there is some repetition in this code. To avoid that you can create an helper like this:

# in app/helpers/respect/application_macros.rb
module Respect
  module ApplicationMacros
    def id(name = "id")
      integer name, greater_than: 0
    end

    def contact_attributes
      string "name", doc: "The name of the contact."
      integer "age", doc: "How old is the contact."
      uri "homepage", doc: "The URL of the contact's homepage"
    end

    def contact
      id
      contact_attributes
      record_timestamps
    end

    def record_timestamps
      doc "When this record has been created."
      datetime "created_at"
      doc "When this record has been updated lastly."
      datetime "updated_at"
    end
  end
end

Notice that we have also provided a macro for the usual id attribute. This helper must be installed in the schema definition DSL like that:

# in config/initializers/respect.rb
Respect::Rails.setup do |config|
  config.helpers Respect::ApplicationMacros
end

Now the request schema can be rewritten like this:

r.body_parameters do |s|
  s.hash "contact" do |s|
    s.contact_attributes
  end
end

and the response schema like that:

r.body do |s|
  s.contact
end

Validate requests and response

All the information you have included in the action specification can also be used to drive a validation process. To enable it you just have to install an "around" filter in your ApplicationController like this:

around_filter :validate_schemas!

Responses formatted in JSON are validated only in development and test mode. When validation failed an exception is raised. To help you debug, we provide a more specific view than the usual exception reporting view of Rails. You can install this view by adding the following line to your ApplicationController:

rescue_from_request_validation_error if Rails.env.development?

Sanitize your incoming parameters

Incoming request parameters must often be sanitized since they come from un-trusted users. A sanitized version of the request parameters is built along the validation process and stored in the request object. You can access it using request.sane_params. Sanitized object may have a more specific type than the original parameter value. For instance the homepage parameter will be a URI object instead of String object:

request.sane_params[:contact][:homepage].class  #=> URI::Generic

You can also automatically sanitize the request parameters in-place by installing this "before" filter:

before_filter :sanitize_params!

Headers documentation

Often REST APIs expect headers to be set in the request and/or responses. Respect for Rails lets you document that using the headers statement available for both the request and the response.

a.request do |r|
  r.headers do |h|
    h.doc "Set this header."
    h['X-AB-Signature'] = "api_public_key"
  end
end

Documentation string

The DSL lets you write documentation string at many places. All these strings are structured with a title on the first line followed by an empty line and a description for the rest of the string. It is much like git commit messages expect that if there is only one paragraph the title will be omit. You can set the documentation like this for most of the items using the doc statement or the :doc option when available. See this example:

doc <<-EOS.strip_heredoc
  The name of the contact.

  First name and last name are separated by white space.
  EOS
string "name"

doc "How old is the contact."
integer "age"

uri "homepage", doc: "The URL of the contact's homepage"

Example

There is an example in this repository. To have a look at it:

$ git clone [email protected]:nicolasdespres/respect-rails.git
$ cd respect-rails/examples/address_book
$ bundle install
$ rake db:create
$ rake db:migrate
$ rails server

Point your favorite web browser to http://localhost:3000/rest_spec.

Getting started

The easiest way to install Respect for Rails is to add it to your Gemfile:

gem "respect-rails", require: "respect/rails"

Then, after running the bundle install command, you can mount the Rails engine provided by this library by adding this line at the beginning of your config/routes.rb file.

mount Respect::Rails::Engine => "/rest_spec"

Then, you can start your application web server as usual and point your web browser to http://localhost:3000/rest_spec/doc.

Getting help

The easiest way to get help about how to use this library is to post your question on the Respect for Rails discussion group. I will be glade to answer. I may have already answered the same question so before you post your question take a bit of time to search the group.

You can also read these documents for further documentation:

Compatibility

Respect for Rails has been tested with:

  • Ruby 1.9.3-p392 (should be compatible with all 1.9.x family)
  • Ruby 2.0.0-p481 (should be compatible with all 2.0.0 family)
  • Rails 3.2.13 and above (3.2.1x)
  • Respect 0.1.0

Note that it uses ActiveSupport::JSON to encode/decode JSON objects.

Feedback

I would love to hear what you think about this library. Feel free to post any comments/remarks on the Respect for Rails discussion group.

Contributing patches

I spent quite a lot of time writing this gem but there is still a lot of work to do. Whether it is a bug-fix, a new feature, some code re-factoring, or documentation clarification, I will be glade to merge your pull-requests on GitHub. You just have to create a branch from master and send me a pull request.

License

Respect for Rails is released under the term of the MIT License. Copyright (c) 2013 Nicolas Despres.