Class: SC.Request
Extends
SC.Copyable, SC.Freezable, SC.Object.
Implements support for AJAX requests using XHR, XHR2 and other protocols.
SC.Request
is essentially a client version of the request/response objects you receive when
implementing HTTP servers.
To send a request, you just need to create your request object, configure your options, and call
send()
to initiate the request. The request will be added to the pending request queue managed
by SC.Request.manager
.
For example,
// Create a simple XHR request.
var request = SC.Request.create();
request.set('address', resourceAddress);
request.set('type', 'GET');
request.send();
The previous example will create an XHR GET request to resourceAddress
. Because the address
and type
of the request must be set on every request, there are helper methods on SC.Request
that you will likely use in every situation.
For example, the previous example can be written more concisely as,
// Create a simple XHR request.
var request = SC.Request.getUrl(resourceAddress);
There are four other helper methods to cover the other common HTTP method types: POST
, DELETE
,
PUT
and PATCH
, which are postUrl
, deleteUrl
, putUrl
and patchUrl
respectively. Since
you may also send a body with POST
, PUT
and PATCH
requests, those helper methods also take a
second argument body
(which is analogous to calling request.set('body', body)
).
Responses
XHR Requests & Custom Communication Protocols
By default, the request will create an instance of SC.XHRResponse
in order to complete the
request. As the name implies, the SC.XHRResponse
class will make an XHR request to the server,
which is the typical method that the SproutCore client will communicate with remote endpoints.
In order to use a custom response type handler, you should extend SC.Response
and set the
responseClass
of the request to your custom response type.
For example,
var request = SC.Request.getUrl(resourceAddress).set('responseClass', MyApp.CustomProtocolResponse);
Handling Responses
SC.Request
supports multiple response handlers based on the status code of the response. This
system is quite intelligent and allows for specific callbacks to handle specific status codes
(e.g. 404) or general status codes (e.g. 400) or combinations of both. Callbacks are registered
using the notify
method, which accepts a target
and a method
which will be called when the
request completes. The most basic example of registering a general response handler would be like
so,
// The response handler target (typically a state or controller or some such SC.Object instance).
var targetObject;
targetObject = SC.Object.create({
handleResponse: function (response) {
// Handle the various possible status codes.
var status = response.get('status');
if (status === 200) { // 200 OK
// Do something.
} else if (status < 400) { // i.e. 3xx
// Do something.
} else ...
}
});
// Create a simple XHR request.
var request;
request = SC.Request.getUrl(resourceAddress)
.notify(targetObject, 'handleResponse')
.send();
However, this approach requires that every response handler be able to handle all of the possible
error codes that we may be able to handle in a more general manner. It's also more code for us
to write to write all of the multiple condition statements. For this reason, the notify
method
accepts an optional status code argument before the target and method. You can use a generic
status code (i.e. 400) or a specific status code (i.e. 404). If you use a generic status code, all
statuses within that range will result in that callback being used.
For example, here is a more specific example,
// The response handler target (typically a data source or state or some such SC.Object instance).
var targetObject;
targetObject = SC.Object.create({
gotOK: function (response) { // 2xx Successful
// Do something.
return true; // Return true to ensure that any following generic handlers don't run!
},
gotForbidden: function (response) { // 403 Forbidden
// Do something.
return true; // Return true to ensure that any following generic handlers don't run!
},
gotUnknownError: function (response) { // 3xx, 4xx (except 403), 5xx
// Do something.
}
});
// Create a simple XHR request.
var request;
request = SC.Request.getUrl(resourceAddress)
.notify(200, targetObject, 'gotOK')
.notify(403, targetObject, 'gotForbidden')
.notify(targetObject, 'gotUnknownError')
.send();
Please note that the notifications will fall through in the order they are added if not handled.
This means that the generic handler gotUnknownError
will be called for any responses not caught
by the other handlers. In this example, to ensure that gotUnknownError
doesn't get called when a
2xx or 403 response comes in, those handlers return true
.
Please also note that this design allows us to easily re-use handler methods. For example, we may
choose to have gotUnknownError
be the standard last resort fallback handler for all requests.
For more examples, including handling of XHR2 progress events, please @see SC.Request.prototype.notify.
Response Bodies & JSON Decoding
The body of the response is the body
property on the response object which is passed to the
notify target method. For example,
gotOK: function (response) { // 2xx Successful
var body = response.get('body');
// Do something.
return true; // Return true to ensure that any following generic handlers don't run!
},
The type of the body will depend on what the server returns, but since it will typically be JSON,
we have a built-in option to have the body be decoded into a JavaScript object automatically by
setting isJSON
to true on the request.
For example,
// Create a simple XHR request.
var request;
request = SC.Request.getUrl(resourceAddress)
.set('isJSON', true)
.notify(200, targetObject, 'gotOK')
.send();
There is a helper method to achieve this as well, json()
,
// Create a simple XHR request.
var request;
request = SC.Request.getUrl(resourceAddress)
.json() // Set `isJSON` to true.
.notify(200, targetObject, 'gotOK')
.send();
Defined in: request.js
- Since:
- SproutCore 1.0
Field Summary
- address
- allowCredentials
- attachIdentifyingHeaders
- body
- encodedBody
- headers
- isAsynchronous
- isJSON
- isSameDomain
- isXML
- responseClass
- source
- timeout
- type
- Fields borrowed from SC.Object:
- concatenatedProperties, isDestroyed, isObject, nextProperty, object, property, target, toInvalidate
- Fields borrowed from SC.Observable:
- isObservable
- Fields borrowed from SC.Copyable:
- isCopyable
- Fields borrowed from SC.Freezable:
- isFreezable, isFrozen
Class Methods
- deleteUrl(address)
- getUrl(address)
- patchUrl(address, body)
- postUrl(address, body)
- putUrl(address, body)
Instance Methods
- async(flag)
- clearHeaders()
- copy()
- credentials(flag)
- didReceive(request, response)
- didSend(request, response)
- header(key, value)
- json(flag)
- notify(statusOrEvent, target, action)
- resend()
- send(body)
- timeoutAfter(timeout)
- willReceive(request, response)
- willSend(request, response)
- xml(flag)
Field Detail
address String- Default value:
- null
Whether to allow credentials, such as Cookies, in the request. While this has no effect on requests to the same domain, cross-domain requests require that the transport be configured to allow the inclusion of credentials such as Cookies.
You can change this property using the chainable credentials()
helper method (or set it directly).
- Default value:
- YES
Specifies whether or not the request will have custom headers attached
to it. By default, SC.Request
attaches X-Requested-With and
X-SproutCore-Version headers to all outgoing requests. This allows
you to override that behavior.
You may want to set this to NO
if you are making simple CORS requests
in compatible browsers. See CORS
Spec for more information.
TODO: Add unit tests for this feature
- Default value:
- YES
The body of the request. May be an object if isJSON
or isXML
is set,
otherwise should be a string.
- Default value:
- null
- Default value:
- #body
Sends the request asynchronously instead of blocking the browser. You should almost always make requests asynchronous. You can change this options with the async() helper option (or simply set it directly).
- Default value:
- YES
Processes the request and response as JSON if possible. You can change this option with the json() helper method.
- Default value:
- NO
Whether the request is within the same domain or not. The response class may use this property to determine specific cross domain configurations.
Process the request and response as XML if possible. You can change this option with the xml() helper method.
- Default value:
- NO
Underlying response class to actually handle this request. Currently the
only supported option is SC.XHRResponse
which uses a traditional
XHR transport.
- Default value:
- SC.XHRResponse
- Default value:
- null
An optional timeout value of the request, in milliseconds. The timer
begins when SC.Response
#fire is actually invoked by the request manager
and not necessarily when SC.Request
#send is invoked. If this timeout is
reached before a response is received, the equivalent of
SC.Request.manager
#cancel() will be invoked on the SC.Response
instance
and the didReceive
() callback will be called.
An exception will be thrown if you try to invoke send() on a request that
has both a timeout and isAsyncronous
set to NO
.
- Default value:
- null
- Default value:
- 'GET'
Class Method Detail
- Parameters:
- address String
- url of request
- Returns:
- SC.Request
- receiver
- Parameters:
- address String
- url of request
- Returns:
- SC.Request
- receiver
- Parameters:
- address String
- url of request
- body String
- Returns:
- SC.Request
- receiver
- Parameters:
- address String
- url of request
- body String
- Returns:
- SC.Request
- receiver
- Parameters:
- address String
- url of request
- body String
- Returns:
- SC.Request
- receiver
Instance Method Detail
- Parameters:
- flag Boolean
- YES to make asynchronous, NO or undefined. Default YES.
- Returns:
- SC.Request
- receiver
Clears the list of headers that were set on this request. This could be used by a subclass to blow-away any custom headers that were added by the super class.
Returns a copy of the current request. This will only copy certain properties so if you want to add additional properties to the copy you will need to override copy() in a subclass.
- Returns:
- SC.Request
- new request
- Parameters:
- flag Boolean
- YES to request allowing credentials, NO to disallow credentials. Default YES.
- Returns:
- SC.Request
- receiver
Invoked after a response has been processed but before any listeners are notified. You can do any standard processing on the request at this point. If you don't want to allow notifications to continue, call response.cancel()
- Parameters:
- request SC.Request
- A copy of the request object, frozen
- response SC.Response
- The object that will wrap the response
Invoked on the original request object just after the request is sent to the server. You might use this callback to update some state in your application.
The passed request is a frozen copy of the request, indicating the options set at the time of the request.
- Parameters:
- request SC.Request
- A copy of the request object, frozen
- response SC.Response
- The object that will wrap the response
- Returns:
- Boolean
- YES on success, NO on failure
To set headers on the request object. Pass either a single key/value pair or a hash of key/value pairs. If you pass only a header name, this will return the current value of the header.
- Parameters:
- key String|Hash
- value String
- Returns:
- SC.Request|Object
- receiver
- Parameters:
- flag Boolean
- YES to make JSON, NO or undefined. Default YES.
- Returns:
- SC.Request
- receiver
Configures a callback to execute as a request progresses or completes. You must pass at least a target and action/method to this and optionally an event name or status code.
You may also pass additional arguments which will then be passed along to your callback.
Scoping With Status Codes
If you pass a status code as the first argument to this method, the
accompanying notification callback will only be called if the response
status matches the status code. For example, if you pass 201 (or
SC.Request.CREATED)
, the accompanying method will only be called if the
response status from the server is also 201.
You can also pass "generic" status codes such as 200, 300, or 400, which
will be invoked anytime the status code is in the same range and if a more
specific notifier was not registered first and returned YES
.
Finally, passing a status code of 0 or no status at all will cause your
method to be executed no matter what the resulting status is unless a
more specific notifier was registered first and returned YES
.
For example,
var req = SC.Request.create({type: 'POST'});
req.notify(201, this, this.reqWasCreated); // Handle a specific status code
req.notify(401, this, this.reqWasUnauthorized); // Handle a specific status code
req.notify(400, this, this.reqDidRedirect); // Handle any 4xx status
req.notify(this, function(response, arg1, arg2) {
// do something
}, arg1, arg2); // Handle any status. Also, passing additional arguments to the callback handler
Notifying on Progress Events
If you pass a progress event name your callback will be called each time
the event fires on the response. For example, the XMLHttpRequest Level 2
specification defines several progress events: loadstart, progress, abort,
error, load, timeout and loadend. Therefore, when using the default
SC.Request
responseClass
, SC.XHRResponse
, you can be notified of each of
these events by simply providing the matching event name.
Note that many older browsers do not support XMLHttpRequest Level 2. See http://caniuse.com/xhr2 for a list of supported browsers.
For example,
var req = SC.Request.create(
{type: 'GET'});
req.notify('progress', this, this.reqDidProgress); // Handle 'progress' events
req.notify('abort', this, this.reqDidAbort); // Handle 'abort' events
req.notify('upload.progress', this, this.reqUploadDidProgress); // Handle 'progress' events on the XMLHttpRequestUpload
req.send();
Callback Format
Your notification callback should expect to receive the Response object as
the first parameter for status code notifications and the Event object for
progress notifications; plus any additional parameters that you pass. If
your callback handles the notification and to prevent further handling, it
should return YES
.
- Parameters:
- statusOrEvent Optional
- {Number|String} A Number status code or String Event name.
- target
- {Object} The target object for the callback action.
- action
- {String|Function} The method name or function to call on the target.
- Returns:
- SC.Request
- The SC.Request object.
Resends the current request. This is more efficient than calling send() for requests that have already been used in a send. Otherwise acts just like send(). Does not take a body argument.
- Returns:
- SC.Response
- new response object
Will fire the actual request. If you have set the request to use JSON mode then you can pass any object that can be converted to JSON as the body. Otherwise you should pass a string body.
- Parameters:
- body String|Object Optional
- Returns:
- SC.Response
- New response object
- Parameters:
- timeout Number
- The timeout in milliseconds.
- Returns:
- SC.Request
- receiver
Invoked when a response has been received but not yet processed. This is your chance to fix up the response based on the results. If you don't want to continue processing the response call response.cancel().
- Parameters:
- request SC.Request
- A copy of the request object, frozen
- response SC.Response
- The object that will wrap the response
Invoked on the original request object just before a copied request is frozen and then sent to the server. This gives you one last change to fixup the request; possibly adding headers and other options.
If you do not want the request to actually send, call cancel().
- Parameters:
- request SC.Request
- A copy of the request object, not frozen
- response SC.Response
- The object that will wrap the response
- Parameters:
- flag Boolean
- YES to make XML, NO or undefined. Default YES.
- Returns:
- SC.Request
- recevier