~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/activeresource/README

  • Committer: Richard Lee (Canonical)
  • Date: 2010-10-15 15:17:58 UTC
  • mfrom: (190.1.3 use-case-mapper)
  • Revision ID: richard.lee@canonical.com-20101015151758-wcvmfxrexsongf9d
Merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
= Active Resource
2
 
 
3
 
Active Resource (ARes) connects business objects and Representational State Transfer (REST)
4
 
web services.  It implements object-relational mapping for REST webservices to provide transparent 
5
 
proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing
6
 
in ActionController::Resources).
7
 
 
8
 
== Philosophy
9
 
 
10
 
Active Resource attempts to provide a coherent wrapper object-relational mapping for REST
11
 
web services. It follows the same philosophy as Active Record, in that one of its prime aims
12
 
is to reduce the amount of code needed to map to these resources.  This is made possible 
13
 
by relying on a number of code- and protocol-based conventions that make it easy for Active Resource
14
 
to infer complex relations and structures.  These conventions are outlined in detail in the documentation
15
 
for ActiveResource::Base.
16
 
 
17
 
== Overview
18
 
 
19
 
Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps model classes to database
20
 
tables.  When a request is made to a remote resource, a REST XML request is generated, transmitted, and the result
21
 
received and serialized into a usable Ruby object.
22
 
 
23
 
=== Configuration and Usage
24
 
 
25
 
Putting ActiveResource to use is very similar to ActiveRecord.  It's as simple as creating a model class
26
 
that inherits from ActiveResource::Base and providing a <tt>site</tt> class variable to it:
27
 
 
28
 
   class Person < ActiveResource::Base
29
 
     self.site = "http://api.people.com:3000/"
30
 
   end
31
 
 
32
 
Now the Person class is REST enabled and can invoke REST services very similarly to how ActiveRecord invokes
33
 
lifecycle methods that operate against a persistent store.
34
 
 
35
 
   # Find a person with id = 1
36
 
   ryan = Person.find(1)
37
 
   Person.exists?(1)  #=> true
38
 
 
39
 
As you can see, the methods are quite similar to Active Record's methods for dealing with database
40
 
records.  But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
41
 
 
42
 
==== Protocol
43
 
 
44
 
Active Resource is built on a standard XML format for requesting and submitting resources over HTTP.  It mirrors the RESTful routing 
45
 
built into ActionController but will also work with any other REST service that properly implements the protocol. 
46
 
REST uses HTTP, but unlike "typical" web applications, it makes use of all the verbs available in the HTTP specification:
47
 
 
48
 
* GET requests are used for finding and retrieving resources.
49
 
* POST requests are used to create new resources.
50
 
* PUT requests are used to update existing resources.
51
 
* DELETE requests are used to delete resources. 
52
 
 
53
 
For more information on how this protocol works with Active Resource, see the ActiveResource::Base documentation;
54
 
for more general information on REST web services, see the article here[http://en.wikipedia.org/wiki/Representational_State_Transfer].
55
 
 
56
 
==== Find
57
 
 
58
 
GET Http requests expect the XML form of whatever resource/resources is/are being requested.  So,
59
 
for a request for a single element - the XML of that item is expected in response:
60
 
 
61
 
   # Expects a response of
62
 
   #
63
 
   # <person><id type="integer">1</id><attribute1>value1</attribute1><attribute2>..</attribute2></person>
64
 
   #
65
 
   # for GET http://api.people.com:3000/people/1.xml
66
 
   #
67
 
   ryan = Person.find(1)
68
 
 
69
 
The XML document that is received is used to build a new object of type Person, with each
70
 
XML element becoming an attribute on the object.
71
 
 
72
 
   ryan.is_a? Person  #=> true
73
 
   ryan.attribute1  #=> 'value1'
74
 
 
75
 
Any complex element (one that contains other elements) becomes its own object:
76
 
 
77
 
   # With this response:
78
 
   #
79
 
   # <person><id>1</id><attribute1>value1</attribute1><complex><attribute2>value2</attribute2></complex></person>
80
 
   #
81
 
   # for GET http://api.people.com:3000/people/1.xml
82
 
   #
83
 
   ryan = Person.find(1)
84
 
   ryan.complex  #=> <Person::Complex::xxxxx>
85
 
   ryan.complex.attribute2  #=> 'value2'
86
 
 
87
 
Collections can also be requested in a similar fashion
88
 
 
89
 
   # Expects a response of
90
 
   #
91
 
   # <people type="array">
92
 
   #  <person><id type="integer">1</id><first>Ryan</first></person>
93
 
   #  <person><id type="integer">2</id><first>Jim</first></person>
94
 
   # </people>
95
 
   #
96
 
   # for GET http://api.people.com:3000/people.xml
97
 
   #
98
 
   people = Person.find(:all)
99
 
   people.first  #=> <Person::xxx 'first' => 'Ryan' ...>
100
 
   people.last  #=> <Person::xxx 'first' => 'Jim' ...>
101
 
 
102
 
==== Create
103
 
 
104
 
Creating a new resource submits the xml form of the resource as the body of the request and expects
105
 
a 'Location' header in the response with the RESTful URL location of the newly created resource.  The
106
 
id of the newly created resource is parsed out of the Location response header and automatically set
107
 
as the id of the ARes object.
108
 
 
109
 
  # <person><first>Ryan</first></person>
110
 
  #
111
 
  # is submitted as the body on
112
 
  #
113
 
  # POST http://api.people.com:3000/people.xml
114
 
  # 
115
 
  # when save is called on a new Person object.  An empty response is
116
 
  # is expected with a 'Location' header value:
117
 
  #
118
 
  # Response (201): Location: http://api.people.com:3000/people/2
119
 
  #
120
 
  ryan = Person.new(:first => 'Ryan')
121
 
  ryan.new?  #=> true
122
 
  ryan.save  #=> true
123
 
  ryan.new?  #=> false
124
 
  ryan.id    #=> 2
125
 
 
126
 
==== Update
127
 
 
128
 
'save' is also used to update an existing resource - and follows the same protocol as creating a resource
129
 
with the exception that no response headers are needed - just an empty response when the update on the
130
 
server side was successful.
131
 
 
132
 
  # <person><first>Ryan</first></person>
133
 
  #
134
 
  # is submitted as the body on
135
 
  #
136
 
  # PUT http://api.people.com:3000/people/1.xml
137
 
  #
138
 
  # when save is called on an existing Person object.  An empty response is
139
 
  # is expected with code (204)
140
 
  #
141
 
  ryan = Person.find(1)
142
 
  ryan.first #=> 'Ryan'
143
 
  ryan.first = 'Rizzle'
144
 
  ryan.save  #=> true
145
 
 
146
 
==== Delete
147
 
 
148
 
Destruction of a resource can be invoked as a class and instance method of the resource.
149
 
 
150
 
  # A request is made to
151
 
  #
152
 
  # DELETE http://api.people.com:3000/people/1.xml
153
 
  #
154
 
  # for both of these forms.  An empty response with
155
 
  # is expected with response code (200)
156
 
  #
157
 
  ryan = Person.find(1)
158
 
  ryan.destroy  #=> true
159
 
  ryan.exists?  #=> false
160
 
  Person.delete(2)  #=> true
161
 
  Person.exists?(2) #=> false
162
 
 
163
 
 
164
 
You can find more usage information in the ActiveResource::Base documentation.
165