# @title Making Requests in Node.js # Making Requests in Node.js A "request" to an AWS service includes the full request and response lifecycle of a call to an operation on a service object, including any retries that are transparently attempted on your behalf. A request is encapsulated in the SDK by the `AWS.Request` object. The semantics of a request are described below, specifically, the support for callbacks, events, and streaming of raw HTTP response data. ## Asynchronous Callbacks All requests made through the SDK are asynchronous and use a callback interface. Each service method that kicks off a request can accept a callback as the last parameter with the signature `function(error, data) { ... }`. This callback will be called when the response or error data is available. For example, the following service method can be called with a standard callback to retrieve the response data or error: ```javascript new AWS.EC2().describeInstances(function(error, data) { if (error) { console.log(error); // an error occurred } else { console.log(data); // request succeeded } }); ``` The `error` and `data` parameters are described in the "Response Object" section below. Note that if you do not specify a callback, the operation will return an `AWS.Request` object that must be manually sent using the `send()` method: ```javascript // create the AWS.Request object var request = new AWS.EC2().describeInstances(); // register a callback to report on the data request.on('success', function(resp) { console.log(resp.data); // log the successful data response }); // send the request request.send(); ``` ### The Response Object (`AWS.Response`) The response object is passed into each callback function so that you can access response data. The `AWS.Response` object that is passed in contains two important properties to get at this data: When using the standard callback mechanism, the two properties will be made available as parameters on the callback method in the form: `function(error, data) { ... }` #### The `data` property The `response.data` property contains the serialized object data retrieved from the service request. For instance, for an Amazon DynamoDB `listTables` method call, the response data might look like this: ```javascript > response.data { TableNames: [ 'table1', 'table2', ... ] } ``` The `data` property can be null if an error occurs (see below). #### The `error` property In the event of a service error (or transfer error), the `response.error` property will be filled with the given error data in the form: ```javascript { code: 'SHORT_UNIQUE_ERROR_CODE', message: 'Some human readable error message' } ``` In the case of an error, the `data` property will be null. Note that if you handle events that can be in a failure state, you should always check whether `response.error` is set before attempting to access the `response.data` property. #### The `request` property Access to the originating request object is available through this property. For example, to access the parameters that were sent with a request: ```javascript s3.getObject({Bucket: 'bucket', Key: 'key'}).on('success', function(response) { console.log("Key was", response.request.params.Key); }).send(); ``` ### Simplified Callback Method Each operation supports a simplified callback that can be passed as the last parameter to any service operation. The callback function should accept an `error` parameter, followed by the `data` from the response. For example: ```javascript s3.listBuckets(function(error, data) { if (err) { console.log(error); // error is Response.error } else { console.log(data); // data is Response.data } }); ``` Prints (assuming the request succeeded): ```javascript { Owner: { ID: '...', DisplayName: '...' }, Buckets: [ { Name: 'someBucketName', CreationDate: someCreationDate }, { Name: 'otherBucketName', CreationDate: otherCreationDate } ], RequestId: '...' } ``` The error and data parameters accepted are equivalent to the `error` and `data` properties discussed in the `AWS.Response` response object section above. If you are passing parameters to the operation, the callback should be placed after the parameters: ``` s3.getObject({Bucket: 'bucket', Key: 'key'}, function(err, data) { // ... }); ``` ### AWS.Request Events You can alternatively register callbacks on events provided by the `AWS.Request` object returned by each service operation method. This request object exposes the `success`, `error`, `complete`, and `httpData` events, each taking a callback that accepts the response object. Note that if you omit the simplified callback parameter on the operation method, you must call `send()` on the returned request object in order to kick off the request to the remote server. #### Event: 'success' ```javascript req.on('success', function(response) { ... }); ``` This event triggers when a successful response from the server is returned. The response contains a `.data` field with the serialized response data from the service. For example: ```javascript s3.listBuckets().done(function(response) { console.log(response.data); }).send(); ``` Prints: ```javascript { Owner: { ID: '...', DisplayName: '...' }, Buckets: [ { Name: 'someBucketName', CreationDate: someCreationDate }, { Name: 'otherBucketName', CreationDate: otherCreationDate } ], RequestId: '...' } ``` #### Event: 'error' ```javascript req.on('error', function(error, response) { ... }); ``` The `error` event works similarly to the `success` event, except that it triggers in the case of a request failure. In this case, `response.data` will be `null` and the `response.error` field will be filled with the error data. Note that the `error` object is also passed directly as the first parameter to the event: ```javascript s3.config.credentials.accessKeyId = 'invalid'; s3.listBuckets().fail(function(error, response) { console.log(error); // or: console.log(response.error); }).send(); ``` Prints: ```javascript { code: 'Forbidden', message: null } ``` #### Event: 'complete' ```javascript req.on('complete', function(response) { ... }); ``` The `complete` event triggers a callback in any final state of a request, i.e., both `success` and `error`. Use this callback to handle any request cleanup that must be executed regardless of the success state. Note that if you do intend to use response data inside of this callback, you must check for the presence of `response.data` or `response.error` before attempting to access either property. For example: ```javascript request.on('complete', function(response) { if (response.error) { // an error occurred, handle it } else { // we can use response.data here } }).send(); ``` #### Event: 'httpData' ```javascript req.on('httpData', function(chunk, response) { ... }); ```

If you register a httpData callback, response.data will still contain serialized output for the entire request. It will be your responsibility to remove the default 'httpData' listener if you do not wish to have the extra parsing and memory overhead from the built-in handlers.

The `httpData` event is used to stream response data from the service packet-by-packet. This event is mostly used for large responses, when it is inefficient (or impossible) to load the entire response into memory. Note that this event contains an extra `chunk` parameter containing the actual data passed on by the server. ## Multiple Callbacks and Chaining You can register multiple callbacks on any request object. The callbacks can be registered for different events, or all for the same event. In addition, you can chain callback registration, for example: ```javascript request. on('success', function(response) { console.log("Success!"); }). on('error', function(response) { console.log("Error!"); }). on('complete', function() { console.log("Always!"); }). send(); ``` The above example will print either "Success! Always!", or "Error! Always!", depending on whether the request succeeded or not. ## Streaming Requests It is possible to stream a request directly to a Node.js Stream object by calling the `createReadStream()` method on a request. This returns a wrapper to the raw HTTP stream used to manage the request, and this data can be piped into any other Node.js stream. This is mostly useful for service operations that return raw data in the payload, like Amazon S3's `getObject` operation, which can be used to stream data directly into a file with this functionality: ```javascript var s3 = new AWS.S3(); var params = {Bucket: 'myBucket', Key: 'myImageFile.jpg'}; var file = require('fs').createWriteStream('/path/to/file.jpg'); s3.getObject(params).createReadStream().pipe(file); ``` The stream object can be used interchangeably as any other Node.js readable Stream object. ### Limitations of Streaming When streaming data from a request using `createReadStream()`, only the raw HTTP data will be returned (the SDK will not do any post-processing on the data). Additionally, if the request initially succeeds, retry logic will be disabled for the rest of the response due to Node.js inability to rewind most streams. This means that in the event of a socket failure in the middle of a connection, the SDK will not attempt to retry and send more data to the stream. It will be your responsibility to manage this logic in your library or application.