188 lines
6.7 KiB
Plaintext
188 lines
6.7 KiB
Plaintext
= Active Resource
|
|
|
|
Active Resource (ARes) connects business objects and Representational State Transfer (REST)
|
|
web services. It implements object-relational mapping for REST web services to provide transparent
|
|
proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing
|
|
in ActionController::Resources).
|
|
|
|
== Philosophy
|
|
|
|
Active Resource attempts to provide a coherent wrapper object-relational mapping for REST
|
|
web services. It follows the same philosophy as Active Record, in that one of its prime aims
|
|
is to reduce the amount of code needed to map to these resources. This is made possible
|
|
by relying on a number of code- and protocol-based conventions that make it easy for Active Resource
|
|
to infer complex relations and structures. These conventions are outlined in detail in the documentation
|
|
for ActiveResource::Base.
|
|
|
|
== Overview
|
|
|
|
Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database
|
|
tables. When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result
|
|
received and serialized into a usable Ruby object.
|
|
|
|
== Download and installation
|
|
|
|
The latest version of Active Support can be installed with Rubygems:
|
|
|
|
% [sudo] gem install activeresource
|
|
|
|
Source code can be downloaded as part of the Rails project on GitHub
|
|
|
|
* https://github.com/rails/rails/tree/master/activeresource/
|
|
|
|
=== Configuration and Usage
|
|
|
|
Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class
|
|
that inherits from ActiveResource::Base and providing a <tt>site</tt> class variable to it:
|
|
|
|
class Person < ActiveResource::Base
|
|
self.site = "http://api.people.com:3000/"
|
|
end
|
|
|
|
Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes
|
|
life cycle methods that operate against a persistent store.
|
|
|
|
# Find a person with id = 1
|
|
ryan = Person.find(1)
|
|
Person.exists?(1) # => true
|
|
|
|
As you can see, the methods are quite similar to Active Record's methods for dealing with database
|
|
records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
|
|
|
|
==== Protocol
|
|
|
|
Active Resource is built on a standard XML format for requesting and submitting resources over HTTP. It mirrors the RESTful routing
|
|
built into Action Controller but will also work with any other REST service that properly implements the protocol.
|
|
REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:
|
|
|
|
* GET requests are used for finding and retrieving resources.
|
|
* POST requests are used to create new resources.
|
|
* PUT requests are used to update existing resources.
|
|
* DELETE requests are used to delete resources.
|
|
|
|
For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation;
|
|
for more general information on REST web services, see the article here[http://en.wikipedia.org/wiki/Representational_State_Transfer].
|
|
|
|
==== Find
|
|
|
|
Find requests use the GET method and expect the XML form of whatever resource/resources is/are being requested. So,
|
|
for a request for a single element, the XML of that item is expected in response:
|
|
|
|
# Expects a response of
|
|
#
|
|
# <person><id type="integer">1</id><attribute1>value1</attribute1><attribute2>..</attribute2></person>
|
|
#
|
|
# for GET http://api.people.com:3000/people/1.xml
|
|
#
|
|
ryan = Person.find(1)
|
|
|
|
The XML document that is received is used to build a new object of type Person, with each
|
|
XML element becoming an attribute on the object.
|
|
|
|
ryan.is_a? Person # => true
|
|
ryan.attribute1 # => 'value1'
|
|
|
|
Any complex element (one that contains other elements) becomes its own object:
|
|
|
|
# With this response:
|
|
#
|
|
# <person><id>1</id><attribute1>value1</attribute1><complex><attribute2>value2</attribute2></complex></person>
|
|
#
|
|
# for GET http://api.people.com:3000/people/1.xml
|
|
#
|
|
ryan = Person.find(1)
|
|
ryan.complex # => <Person::Complex::xxxxx>
|
|
ryan.complex.attribute2 # => 'value2'
|
|
|
|
Collections can also be requested in a similar fashion
|
|
|
|
# Expects a response of
|
|
#
|
|
# <people type="array">
|
|
# <person><id type="integer">1</id><first>Ryan</first></person>
|
|
# <person><id type="integer">2</id><first>Jim</first></person>
|
|
# </people>
|
|
#
|
|
# for GET http://api.people.com:3000/people.xml
|
|
#
|
|
people = Person.all
|
|
people.first # => <Person::xxx 'first' => 'Ryan' ...>
|
|
people.last # => <Person::xxx 'first' => 'Jim' ...>
|
|
|
|
==== Create
|
|
|
|
Creating a new resource submits the XML form of the resource as the body of the request and expects
|
|
a 'Location' header in the response with the RESTful URL location of the newly created resource. The
|
|
id of the newly created resource is parsed out of the Location response header and automatically set
|
|
as the id of the ARes object.
|
|
|
|
# <person><first>Ryan</first></person>
|
|
#
|
|
# is submitted as the body on
|
|
#
|
|
# POST http://api.people.com:3000/people.xml
|
|
#
|
|
# when save is called on a new Person object. An empty response is
|
|
# is expected with a 'Location' header value:
|
|
#
|
|
# Response (201): Location: http://api.people.com:3000/people/2
|
|
#
|
|
ryan = Person.new(:first => 'Ryan')
|
|
ryan.new? # => true
|
|
ryan.save # => true
|
|
ryan.new? # => false
|
|
ryan.id # => 2
|
|
|
|
==== Update
|
|
|
|
'save' is also used to update an existing resource - and follows the same protocol as creating a resource
|
|
with the exception that no response headers are needed - just an empty response when the update on the
|
|
server side was successful.
|
|
|
|
# <person><first>Ryan</first></person>
|
|
#
|
|
# is submitted as the body on
|
|
#
|
|
# PUT http://api.people.com:3000/people/1.xml
|
|
#
|
|
# when save is called on an existing Person object. An empty response is
|
|
# is expected with code (204)
|
|
#
|
|
ryan = Person.find(1)
|
|
ryan.first # => 'Ryan'
|
|
ryan.first = 'Rizzle'
|
|
ryan.save # => true
|
|
|
|
==== Delete
|
|
|
|
Destruction of a resource can be invoked as a class and instance method of the resource.
|
|
|
|
# A request is made to
|
|
#
|
|
# DELETE http://api.people.com:3000/people/1.xml
|
|
#
|
|
# for both of these forms. An empty response with
|
|
# is expected with response code (200)
|
|
#
|
|
ryan = Person.find(1)
|
|
ryan.destroy # => true
|
|
ryan.exists? # => false
|
|
Person.delete(2) # => true
|
|
Person.exists?(2) # => false
|
|
|
|
== License
|
|
|
|
Active Support is released under the MIT license.
|
|
|
|
== Support
|
|
|
|
API documentation is at
|
|
|
|
* http://api.rubyonrails.org
|
|
|
|
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
|
|
|
|
* https://github.com/rails/rails/issues
|
|
|
|
You can find more usage information in the ActiveResource::Base documentation.
|