diff options
Diffstat (limited to 'activeresource/README.rdoc')
-rw-r--r-- | activeresource/README.rdoc | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/activeresource/README.rdoc b/activeresource/README.rdoc new file mode 100644 index 0000000000..127ac5b4a9 --- /dev/null +++ b/activeresource/README.rdoc @@ -0,0 +1,165 @@ += 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. + +=== 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 +lifecycle 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.find(: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 + + +You can find more usage information in the ActiveResource::Base documentation. + |