ActiveResource::Base is the main class for mapping
RESTful resources as models in a Rails
application.
For an outline of what Active Resource is capable of, see files/vendor/rails/activeresource/README.html.
Automated mapping
Active Resource objects represent your RESTful resources as manipulatable
Ruby objects. To map resources to Ruby objects, Active Resource only needs
a class name that corresponds to the resource name (e.g., the class Person
maps to the resources people, very similarly to Active Record) and a site value, which holds the URI of the
resources.
class Person < ActiveResource::Base
self.site = "http://api.people.com:3000/"
end
Now the Person class is mapped to RESTful resources located at api.people.com:3000/people/,
and you can now use Active Resource‘s lifecycles methods to
manipulate resources. In the case where you already have an existing model
with the same name as the desired RESTful resource you can set the
element_name value.
class PersonResource < ActiveResource::Base
self.site = "http://api.people.com:3000/"
self.element_name = "person"
end
Lifecycle methods
Active Resource exposes methods for creating, finding, updating, and
deleting resources from REST web services.
ryan = Person.new(:first => 'Ryan', :last => 'Daigle')
ryan.save # => true
ryan.id # => 2
Person.exists?(ryan.id) # => true
ryan.exists? # => true
ryan = Person.find(1)
# Resource holding our newly created Person object
ryan.first = 'Rizzle'
ryan.save # => true
ryan.destroy # => true
As you can see, these are very similar to Active Record‘s lifecycle
methods for database records. You can read more about each of these methods
in their respective documentation.
Custom REST methods
Since simple CRUD/lifecycle methods can‘t accomplish every task,
Active Resource also supports defining your own custom REST methods. To
invoke them, Active Resource provides the get, post,
put and \delete methods
where you can specify a custom REST method name to invoke.
# POST to the custom 'register' REST method, i.e. POST /people/new/register.xml.
Person.new(:name => 'Ryan').post(:register)
# => { :id => 1, :name => 'Ryan', :position => 'Clerk' }
# PUT an update by invoking the 'promote' REST method, i.e. PUT /people/1/promote.xml?position=Manager.
Person.find(1).put(:promote, :position => 'Manager')
# => { :id => 1, :name => 'Ryan', :position => 'Manager' }
# GET all the positions available, i.e. GET /people/positions.xml.
Person.get(:positions)
# => [{:name => 'Manager'}, {:name => 'Clerk'}]
# DELETE to 'fire' a person, i.e. DELETE /people/1/fire.xml.
Person.find(1).delete(:fire)
For more information on using custom REST methods, see the ActiveResource::CustomMethods documentation.
You can validate resources client side by overriding validation methods in
the base class.
class Person < ActiveResource::Base
self.site = "http://api.people.com:3000/"
protected
def validate
errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
end
end
See the ActiveResource::Validations
documentation for more information.
Authentication
Many REST APIs will require authentication, usually in the form of basic
HTTP authentication. Authentication can be specified by:
- putting the credentials in the URL for the site variable.
class Person < ActiveResource::Base
self.site = "http://ryan:password@api.people.com:3000/"
end
- defining user and/or password variables
class Person < ActiveResource::Base
self.site = "http://api.people.com:3000/"
self.user = "ryan"
self.password = "password"
end
For obvious security reasons, it is probably best if such services are
available over HTTPS.
Note: Some values cannot be provided in the URL passed to site. e.g. email addresses as usernames. In
those situations you should use the separate user and password option.
Errors & Validation
Error handling and validation is handled in much the same manner as
you‘re used to seeing in Active Record. Both the response code in the
HTTP response and the body of the response are used to indicate that an
error occurred.
Resource errors
When a GET is requested for a resource that does not exist, the HTTP
404 (Resource Not Found) response code will be returned from the
server which will raise an ActiveResource::ResourceNotFound
exception.
# GET http://api.people.com:3000/people/999.xml
ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
404 is just one of the HTTP error response codes that Active
Resource will handle with its own exception. The following HTTP response
codes will also result in these exceptions:
These custom exceptions allow you to deal with resource errors more
naturally and with more precision rather than returning a general HTTP
error. For example:
begin
ryan = Person.find(my_id)
rescue ActiveResource::ResourceNotFound
redirect_to :action => 'not_found'
rescue ActiveResource::ResourceConflict, ActiveResource::ResourceInvalid
redirect_to :action => 'new'
end
Validation errors
Active Resource supports validations on resources and will return errors if
any these validations fail (e.g., "First name can not be blank"
and so on). These types of errors are denoted in the response by a response
code of 422 and an XML representation of the validation errors.
The save operation will then fail (with a
false return value) and the validation errors can be accessed on
the resource in question.
ryan = Person.find(1)
ryan.first # => ''
ryan.save # => false
# When
# PUT http://api.people.com:3000/people/1.xml
# is requested with invalid values, the response is:
#
# Response (422):
# <errors type="array"><error>First cannot be empty</error></errors>
#
ryan.errors.invalid?(:first) # => true
ryan.errors.full_messages # => ['First cannot be empty']
Learn more about Active Resource‘s validation features in the ActiveResource::Validations documentation.
Timeouts
Active Resource relies on HTTP to access RESTful APIs and as such is
inherently susceptible to slow or unresponsive servers. In such cases, your
Active Resource method calls could \timeout. You can control the amount of time
before Active Resource times out with the timeout variable.
class Person < ActiveResource::Base
self.site = "http://api.people.com:3000/"
self.timeout = 5
end
This sets the timeout to 5
seconds. You can adjust the timeout to a value suitable for the
RESTful API you are accessing. It is recommended to set this to a
reasonably low value to allow your Active Resource clients (especially if
you are using Active Resource in a Rails
application) to fail-fast (see en.wikipedia.org/wiki/Fail-fast)
rather than cause cascading failures that could incapacitate your server.
When a \timeout occurs, an ActiveResource::TimeoutError is raised. You
should rescue from ActiveResource::TimeoutError in your Active
Resource method calls.
Internally, Active Resource relies on Ruby‘s Net::HTTP library to
make HTTP requests. Setting timeout sets the read_timeout of
the internal Net::HTTP instance to the same value. The default
read_timeout is 60 seconds on most Ruby implementations.