Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / data / proxy / Rest.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @author Ed Spencer
17  * @class Ext.data.proxy.Rest
18  * @extends Ext.data.proxy.Ajax
19  * 
20  * <p>RestProxy is a specialization of the {@link Ext.data.proxy.Ajax AjaxProxy} which simply maps the four actions 
21  * (create, read, update and destroy) to RESTful HTTP verbs. For example, let's set up a {@link Ext.data.Model Model}
22  * with an inline RestProxy</p>
23  * 
24 <pre><code>
25 Ext.define('User', {
26     extend: 'Ext.data.Model',
27     fields: ['id', 'name', 'email'],
28
29     proxy: {
30         type: 'rest',
31         url : '/users'
32     }
33 });
34 </code></pre>
35  * 
36  * <p>Now we can create a new User instance and save it via the RestProxy. Doing this will cause the Proxy to send a
37  * POST request to '/users':
38  * 
39 <pre><code>
40 var user = Ext.ModelManager.create({name: 'Ed Spencer', email: 'ed@sencha.com'}, 'User');
41
42 user.save(); //POST /users
43 </code></pre>
44  * 
45  * <p>Let's expand this a little and provide a callback for the {@link Ext.data.Model#save} call to update the Model
46  * once it has been created. We'll assume the creation went successfully and that the server gave this user an ID of 
47  * 123:</p>
48  * 
49 <pre><code>
50 user.save({
51     success: function(user) {
52         user.set('name', 'Khan Noonien Singh');
53
54         user.save(); //PUT /users/123
55     }
56 });
57 </code></pre>
58  * 
59  * <p>Now that we're no longer creating a new Model instance, the request method is changed to an HTTP PUT, targeting
60  * the relevant url for that user. Now let's delete this user, which will use the DELETE method:</p>
61  * 
62 <pre><code>
63     user.destroy(); //DELETE /users/123
64 </code></pre>
65  * 
66  * <p>Finally, when we perform a load of a Model or Store, RestProxy will use the GET method:</p>
67  * 
68 <pre><code>
69 //1. Load via Store
70
71 //the Store automatically picks up the Proxy from the User model
72 var store = new Ext.data.Store({
73     model: 'User'
74 });
75
76 store.load(); //GET /users
77
78 //2. Load directly from the Model
79
80 //GET /users/123
81 Ext.ModelManager.getModel('User').load(123, {
82     success: function(user) {
83         console.log(user.getId()); //outputs 123
84     }
85 });
86 </code></pre>
87  * 
88  * <p><u>Url generation</u></p>
89  * 
90  * <p>RestProxy is able to automatically generate the urls above based on two configuration options - {@link #appendId}
91  * and {@link #format}. If appendId is true (it is by default) then RestProxy will automatically append the ID of the 
92  * Model instance in question to the configured url, resulting in the '/users/123' that we saw above.</p>
93  * 
94  * <p>If the request is not for a specific Model instance (e.g. loading a Store), the url is not appended with an id. 
95  * RestProxy will automatically insert a '/' before the ID if one is not already present.</p>
96  * 
97 <pre><code>
98 new Ext.data.proxy.Rest({
99     url: '/users',
100     appendId: true //default
101 });
102
103 // Collection url: /users
104 // Instance url  : /users/123
105 </code></pre>
106  * 
107  * <p>RestProxy can also optionally append a format string to the end of any generated url:</p>
108  * 
109 <pre><code>
110 new Ext.data.proxy.Rest({
111     url: '/users',
112     format: 'json'
113 });
114
115 // Collection url: /users.json
116 // Instance url  : /users/123.json
117 </code></pre>
118  * 
119  * <p>If further customization is needed, simply implement the {@link #buildUrl} method and add your custom generated
120  * url onto the {@link Ext.data.Request Request} object that is passed to buildUrl. See 
121  * <a href="source/RestProxy.html#method-Ext.data.proxy.Rest-buildUrl">RestProxy's implementation</a> for an example of
122  * how to achieve this.</p>
123  * 
124  * <p>Note that RestProxy inherits from {@link Ext.data.proxy.Ajax AjaxProxy}, which already injects all of the sorter,
125  * filter, group and paging options into the generated url. See the {@link Ext.data.proxy.Ajax AjaxProxy docs} for more
126  * details.</p>
127  */
128 Ext.define('Ext.data.proxy.Rest', {
129     extend: 'Ext.data.proxy.Ajax',
130     alternateClassName: 'Ext.data.RestProxy',
131     alias : 'proxy.rest',
132     
133     /**
134      * @cfg {Boolean} appendId True to automatically append the ID of a Model instance when performing a request based
135      * on that single instance. See RestProxy intro docs for more details. Defaults to true.
136      */
137     appendId: true,
138     
139     /**
140      * @cfg {String} format Optional data format to send to the server when making any request (e.g. 'json'). See the
141      * RestProxy intro docs for full details. Defaults to undefined.
142      */
143     
144     /**
145      * @cfg {Boolean} batchActions True to batch actions of a particular type when synchronizing the store.
146      * Defaults to <tt>false</tt>.
147      */
148     batchActions: false,
149     
150     /**
151      * Specialized version of buildUrl that incorporates the {@link #appendId} and {@link #format} options into the
152      * generated url. Override this to provide further customizations, but remember to call the superclass buildUrl
153      * so that additional parameters like the cache buster string are appended
154      */
155     buildUrl: function(request) {
156         var me        = this,
157             operation = request.operation,
158             records   = operation.records || [],
159             record    = records[0],
160             format    = me.format,
161             url       = me.getUrl(request),
162             id        = record ? record.getId() : operation.id;
163         
164         if (me.appendId && id) {
165             if (!url.match(/\/$/)) {
166                 url += '/';
167             }
168             
169             url += id;
170         }
171         
172         if (format) {
173             if (!url.match(/\.$/)) {
174                 url += '.';
175             }
176             
177             url += format;
178         }
179         
180         request.url = url;
181         
182         return me.callParent(arguments);
183     }
184 }, function() {
185     Ext.apply(this.prototype, {
186         /**
187          * Mapping of action name to HTTP request method. These default to RESTful conventions for the 'create', 'read',
188          * 'update' and 'destroy' actions (which map to 'POST', 'GET', 'PUT' and 'DELETE' respectively). This object should
189          * not be changed except globally via {@link Ext#override Ext.override} - the {@link #getMethod} function can be overridden instead.
190          * @property actionMethods
191          * @type Object
192          */
193         actionMethods: {
194             create : 'POST',
195             read   : 'GET',
196             update : 'PUT',
197             destroy: 'DELETE'
198         }
199     });
200 });
201