1
0
Fork 0
liza/src/server/request/UserResponse.js

276 lines
7.3 KiB
JavaScript

/**
* Response to user request
*
* Copyright (C) 2017 LoVullo Associates, Inc.
*
* This file is part of the Liza Data Collection Framework.
*
* liza is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Class = require( 'easejs' ).Class,
UserRequest = require( './UserRequest' );
/**
* Abstraction for standard user request responses
*
* This provides consistency throughout the system and permits hiding the
* actual user request. This may be extended by subtypes to alter its
* behavior in a well-defined manner.
*/
module.exports = Class( 'UserResponse' )
.extend(
{
/**
* User request to accept a response
* @type {UserRequest}
*/
'private _request': null,
__construct: function( request )
{
if ( !Class.isA( UserRequest, request ) )
{
throw TypeError(
"UserRequest expected; given " + request
);
}
this._request = request;
},
/**
* Satisfy a request successfully
*
* This is an HTTP/1.1 200 OK response.
*
* @param {*} data return data
*
* @return {undefined} only one response should be made
*/
'public ok': function( data )
{
this._reply( 200, null, data );
},
/**
* Request was accepted for processing and may or may not eventually
* complete
*
* This is an HTTP/1.1 202 Accepted response.
*
* @param {*} data return data
*
* @return {undefined} only one response should be made
*/
'public accepted': function( data )
{
this._reply( 202, null, data );
},
/**
* Client request was unknown or invalid
*
* This is an HTTP/1.1 400 Bad Request response.
*
* @param {*} data return data
* @param {?string} error error code or description
*
* @return {undefined} only one response should be made
*/
'public requestError': function( data, error )
{
this._reply( 400, error, data );
},
/**
* Request cannot be completed due to a conflict with the current state
* of the resource
*
* This is an HTTP/1.1 409 Conflict response.
*
* @param {*} data return data
* @param {?string} error error code or description
*
* @return {undefined} only one response should be made
*/
'public stateError': function( data, error )
{
this._reply( 409, error, data );
},
/**
* User is not authorized to perform the action
*
* This is an HTTP/1.1 403 Forbidden response.
*
* @param {*} data return data
* @param {?string} error error code or description
*
* @return {undefined} only one response should be made
*/
'public forbidden': function( data, error )
{
this._reply( 403, error, data );
},
/**
* Requested resource was not found
*
* This is an HTTP/1.1 404 Not Found response.
*
* @param {*} data return data
* @param {?string} error error code or description
*
* @return {undefined} only one response should be made
*/
'public notFound': function( data, error )
{
this._reply( 404, error, data );
},
/**
* An internal error occurred while processing an otherwise valid
* request
*
* This is an HTTP/1.1 500 Internal Server Error response.
*
* @param {*} data return data
* @param {?string} error error code or description
*
* @return {undefined} only one response should be made
*/
'public internalError': function( data, error )
{
this._reply( 500, error, data );
},
/**
* Requested service is unavailable and the request could not be
* fulfilled
*
* This is an HTTP/1.1 503 Service Unavailable response.
*
* @param {*} data return data
* @param {?string} error error code or description
*
* @return {undefined} only one response should be made
*/
'public unavailable': function( data, error )
{
this._reply( 503, error, data );
},
/**
* Requested service is temporarily unavailable and the request should
* be retried
*
* This invokes `#unavailable` with a static error code of `EAGAIN`
* (motivated by the standard Unix error constant name).
*
* @param {*} data return data
*
* @return {undefined} only one response should be made
*/
'public tryAgain': function( data )
{
this.unavailable( data, 'EAGAIN' );
},
/**
* Prepare to complete a request with the given code and data
*
* The majority of this logic is delegated to `#endRequest`, allowing
* subtypes to hook or override the response logic.
*
* @param {number} code status code
* @param {?string} error error string, if applicable
* @param {*} data generic return data
*/
'protected _reply': function( code, error, data )
{
code = +code;
error = ''+( error || '' ) || null;
// this may be overridden by subtypes
this.endRequest( code, error, data );
},
/**
* Complete a request with the given code and data
*
* The returned are serialized, so keep in mind that certain data
* may be lost (for example, the distinction between `null` and
* `undefined`).
*
* A subtype may override this method to hook or fundamentally alter the
* behavior of a response. If a subtype only wishes to modify or
* augment the response, it should instead override `#createRreply`.
*
* @param {number} code status code
* @param {?string} error error string, if applicable
* @param {*} data generic return data
*/
'virtual protected endRequest': function( code, error, data )
{
this._request
.setResponseCode( code )
.end(
JSON.stringify(
this.createReply( code, error, data )
)
);
},
/**
* Produce a response to be returned to the client
*
* The standard reply consists of an error string (or null) and generic
* response data, output as a JSON object literal.
*
* If a subtype wishes to augment the response in any way, this is the
* place to do it.
*
* The return value will be serialized.
*
* @param {?string} error error string, if applicable
* @param {*} data generic return data
*
* @return {*} response value
*/
'virtual protected createReply': function( code, error, data )
{
return {
error: error,
data: data,
};
},
} );