README.md in restfulness-0.2.2 vs README.md in restfulness-0.2.3
- old
+ new
@@ -142,11 +142,13 @@
bundle exec rackup
```
For a very simple example project, checkout the `/example` directory in the source code.
+If you're using Restulfness in a Rails project, you'll want to checkout the Reloading section below.
+
### Routes
The aim of routes in Restfulness are to be stupid simple. These are the basic rules:
* Each route is an array that forms a path when joined with `/`.
@@ -288,15 +290,31 @@
# Request params
request.params # {'key' => 'value'} - usually a JSON deserialized object
```
+### Logging
+
+By default, Restfulness uses `ActiveSupport::Logger.new(STDOUT)` as its logger.
+
+To change the logger:
+
+```ruby
+Restfulness.logger = Rack::NullLogger.new(My::Api)
+```
+
+By default, any parameter with key prefix `password` will be sanitized in the log. To change the sensitive parameters:
+
+```ruby
+Restfulness.sensitive_params = [:password, :secretkey]
+```
+
## 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:
+One of the easiest approaches is 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)
@@ -313,11 +331,11 @@
```ruby
class ProjectResource < Restfulness::Resource
def patch
unless project.update_attributes(request.params)
- forbidden!(project.errors)
+ forbidden! project.errors
end
project
end
end
```
@@ -350,11 +368,11 @@
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.
+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 JSON error payload, or even just resort to a simple string.
The currently built in error methods are:
* `not_modified!`
* `bad_request!`
@@ -365,51 +383,160 @@
* `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:
+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
```
+## Reloading
-## Caveats and TODOs
+We're all used to the way Rails projects magically reload files so you don't have to restart the server after each change. Depending on the way you use Restfulness in your project, this can be supported.
-Restfulness is still very much a work in progress. Here is a list of things that we'd like to improve or fix:
+### The Rails Way
- * 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.
+Using Restfulness in Rails is the easiest way to take advantage support reloading.
-## Reloading
+The recomended approach is to create two directories in your Rails projects `/app` path:
-Reloading is complicated. Unfortunately we're all used to the way Rails projects magically reload changed files so you don't have to restart the server after each change.
+ * `/app/apis` can be used for defining your API route files, and
+ * `/app/resources` for defining a tree of resource definition files.
-If you're using Restfulness as a standalone project, we recommend using a rack extension like [Shotgun](https://github.com/rtomayko/shotgun).
+Add the two paths to your rails autoloading configuration in `/config/application.rb`, there will already be a sample in your config provided by Rails:
-If you're adding Restfulness to a Rails project, you can take advantage of the `ActionDispatch::Reloader` rack middleware. Simply include it in the application definition:
+```ruby
+# Custom directories with classes and modules you want to be autoloadable.
+config.autoload_paths += %W( #{config.root}/app/resources #{config.root}/app/apis )
+```
+Your Resource and API files will now be autoloadable from your Rails project. The next step is to update our Rails router to be able to find our API. Modify the `/config/routes.rb` file so that it looks something like the following:
+
```ruby
-class MyAPI < Restfulness::Application
+YourRailsApp::Application.routes.draw do
+
+ # Autoreload the API in development
if Rails.env.development?
- middlewares << ActionDispatch::Reloader
+ mount Api.new => '/api'
end
- routes do
- # etc. etc.
+
+ #.... rest of routes
+end
+
+```
+
+You'll see in the code sample that we're only loading the Restfulness API during development. Our recommendation is to use Restfulness as close to Rack as possible and avoid any of the Rails overhead. To support request in production, you'll need to update your `/config.rb` so that it looks something like the following:
+
+```ruby
+# This file is used by Rack-based servers to start the application.
+require ::File.expand_path('../config/environment', __FILE__)
+
+map = {
+ "/" => YourRailsApp::Application
+}
+unless Rails.env.development?
+ map["/api"] = Api.new
+end
+
+run Rack::URLMap.new(map)
+```
+
+Thats all there is to it! You'll now have auto-reloading in Rails, and fast request handling in production. Just be sure to be careful in development that none of your other Rack middleware interfere with Restfulness. In a new Rails project this certainly won't be an issue.
+
+### The Rack Way
+
+If you're using Restfulness as a standalone project, we recommend using a rack extension like [Shotgun](https://github.com/rtomayko/shotgun).
+
+
+## Writing Tests
+
+Test your application by creating requests to your resources and making assertions about the responses.
+
+### RSpec
+
+Configure `rack-test` to be included in your resource specs. One way to does this would be to create a new file `/spec/support/example_groups/restfulness_resource_example_group.rb` with something similar to the following:
+
+```ruby
+module RestfulnessResourceExampleGroup
+ extend ActiveSupport::Concern
+ include Rack::Test::Methods
+
+ # Used by Rack::Test. This could be defined per spec if you have multiple Apps
+ def app
+ My::Api.new
end
+ protected :app
+
+ # Set the request content type for a JSON payload
+ def set_content_type_json
+ header('content-type', 'application/json; charset=utf-8')
+ end
+
+ # Helper method to POST a json payload
+ # post(uri, params = {}, env = {}, &block)
+ def post_json(uri, json_data = {}, env = {}, &block)
+ set_content_type_json
+ post(uri, json_data.to_json, &block)
+ end
+
+ included do
+ metadata[:type] = :restfulness_resource
+ end
+
+ # Setup RSpec to include RestfulnessResourceExampleGroup for all specs in given folder(s)
+ RSpec.configure do |config|
+ config.include self,
+ :type => :restfulness_resource,
+ :example_group => { :file_path => %r(spec/resources) }
+ end
+
+ # silence logger
+ Restfulness.logger = Rack::NullLogger.new(My::Api)
end
```
-We're still working on ways to improve this. If you have any ideas, please send me a pull request!
+Make sure in your `spec_helper` all files in the support folder and sub-directories are being loaded. You should have something like the following:
+```ruby
+Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
+```
+
+Now you can add a resource spec in the `spec/resources` directory. Here's an example
+
+```ruby
+require 'spec_helper'
+
+describe SessionResource do
+
+ let(:user) { create(:user) }
+
+ context 'GET' do
+ it 'returns 401 if not authorized' do
+ get 'api/session' do |response|
+ expect(response.status).to eq 401
+ end
+ end
+ end
+
+ context 'POST' do
+ it 'returns 200 when request with correct user info' do
+ post_json 'api/session', {:email => user.email, :password => user.password} do |response|
+ expect(response.status).to eq 200
+ end
+ end
+ end
+end
+```
+
+See [Rack::Test](https://github.com/brynary/rack-test) for more information.
+
+A useful gem for making assertions about json objects is [json_spec](https://github.com/collectiveidea/json_spec). This could be included in your `RestfulnessResourceExampleGroup`.
+
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Write your code and test the socks off it!
@@ -419,11 +546,36 @@
## Contributors
Restfulness was created by Sam Lown <me@samlown.com> as a solution for building simple APIs at [Cabify](http://www.cabify.com).
+The project is now awesome, thanks to contributions by:
+ * [Adam Williams](https://github.com/awilliams)
+
+
+## Caveats and TODOs
+
+Restfulness is still a work in progress but at Cabify we are using it in production. Here is a list of things that we'd like to improve or fix:
+
+ * Support for more serializers and content types, not just JSON.
+ * Support path methods for automatic URL generation.
+ * Support redirect exceptions.
+ * Needs more functional testing.
+ * Support for before and after filters in resources, although I'm slightly aprehensive about this.
+
## History
+
+### 0.2.3 - pending
+
+ * Fixing issue where query parameters are set as Hash instead of HashWithIndifferentAccess.
+ * Rewinding the body, incase rails got there first.
+ * Updating the README to describe auto-reloading in Rails projects.
+ * Improved handling of Content-Type header that includes encoding. (@awilliams)
+ * Return 400 error when malformed JSON is provided in body (@awilliams)
+ * Updated documentation to describe resource testing (@awilliams)
+ * Now supports filtering of sensitive query and parameter request values (@awilliams)
+ * Adding support for X-HTTP-Method-Override header. (@samlown)
### 0.2.2 - October 31, 2013
* Refactoring logging support to not depend on Rack CommonLogger nor ShowExceptions.
* Using ActiveSupport::Logger instead of MonoLogger.