README.md in restfulness-0.1.0 vs README.md in restfulness-0.2.0

- old
+ new

@@ -25,11 +25,11 @@ get :public_timeline do Status.limit(20) end desc "Return a personal timeline." - get :home_timeline do + get :home_timeline do authenticate! current_user.statuses.limit(20) end desc "Return a status." @@ -126,12 +126,10 @@ "/" => MyRailsApp::Application, "/api" => MyAppAPI.new ) ``` -By default, Restfulness comes with a Rack compatible dispatcher, but in the future it might make sense to add others. - If you want to run Restfulness standalone, simply create a `config.ru` that will load up your application: ```ruby require 'my_app' run MyApp.new @@ -141,11 +139,11 @@ ``` bundle exec rackup ``` -For an example, checkout the `/example` directory in the source code. +For a very simple example project, checkout the `/example` directory in the source code. ### Routes The aim of routes in Restfulness are to be stupid simple. These are the basic rules: @@ -177,10 +175,11 @@ Resources are like Controllers in a Rails project. They handle the basic HTTP actions using methods that match the same name as the action. The result of an action is serialized into a JSON object automatically. The actions supported by a resource are: * `get` * `head` * `post` + * `patch` * `put` * `delete` * `options` - this is the only action provded by default When creating your resource, simply define the methods you'd like to use and ensure each has a result: @@ -190,12 +189,12 @@ # Return the basic object def get project end - # Update the object - def put + # Update the existing object with some new attributes + def patch project.update(params) end protected @@ -288,15 +287,103 @@ # Request params request.params # {'key' => 'value'} - usually a JSON deserialized object ``` +## Error Handling + +If you want your application to return anything other than a 200 (or 202) status, you have a couple of options that allow you to send codes back to the client. + +The easiest method is probably just to update the `response` code. Take the following example where we set a 403 response and the model's errors object in the payload: + +```ruby +class ProjectResource < Restfulness::Resource + def patch + if project.update_attributes(request.params) + project + else + response.status = 403 + project.errors + end + end +end +``` + +The favourite method in Restfulness however is to use the `HTTPException` class and helper methods that will raise the error for you. For example: + +```ruby +class ProjectResource < Restfulness::Resource + def patch + unless project.update_attributes(request.params) + forbidden!(project.errors) + end + project + end +end +``` + +The `forbidden!` bang method will call the `error!` method, which in turn will raise an `HTTPException` with the appropriate status code. Exceptions are permitted to include a payload also, so you could override the `error!` method if you wished with code that will automatically re-format the payload. Another example: + +```ruby +# Regular resource +class ProjectResource < ApplicationResource + def patch + unless project.update_attributes(request.params) + forbidden!(project) # only send the project object! + end + project + end +end + +# Main Application Resource +class ApplicationResource < Restfulness::Resource + # Overwrite the regular error handler so we can provide + # our own format. + def error!(status, payload = "", opts = {}) + case payload + when ActiveRecord::Base # or your favourite ORM + payload = { + :errors => payload.errors.full_messages + } + end + super(status, payload, opts) + end +end + +``` + +This can be a really nice way to mold your errors into a standard format. All HTTP exceptions generated inside resources will pass through `error!`, even those that a triggered by a callback. It gives a great way to provide your own more complete result, or even just resort to a simple string. + +The currently built in error methods are: + + * `not_modified!` + * `bad_request!` + * `unauthorized!` + * `payment_required!` + * `forbidden!` + * `resource_not_found!` + * `request_timeout!` + * `conflict!` + * `gone!` + * `unprocessable_entity!` + +If you'd like to see me more, please send us a pull request! Failing that, you can create your own by writing something along the lines of: + +```ruby +def im_a_teapot!(payload = "") + error!(418, payload) +end +``` + + ## Caveats and TODOs Restfulness is still very much a work in progress. Here is a list of things that we'd like to improve or fix: - * Support for more serializers, not just JSON. + * Support for more serializers and content types, not just JSON. + * Support path methods for automatic URL generation. + * Support redirect exceptions. * Reloading is a PITA (see note below). * Needs more functional testing. * Support for before and after filters in resources, although I'm slightly aprehensive about this. ## Reloading @@ -332,9 +419,13 @@ Restfulness was created by Sam Lown <me@samlown.com> as a solution for building simple APIs at [Cabify](http://www.cabify.com). ## History + +### 0.2.0 - October 17, 2013 + +Refactoring error handling and reporting so that it is easier to use and simpler. ### 0.1.0 - October 16, 2013 First release!