bin/server/request.js
function Request(server, keys, rejectable, config) {
    if (!config) config = {};
    if (typeof config !== 'object') config = { path: config };

    const promise = new Promise((resolve, reject) => {
        let fulfilled = false;

        this.on('res-complete', () => {
            if (fulfilled) {
                req.log('fulfilled', 'Already fulfilled');
            } else {
                fulfilled = true;
                req.log('fulfilled');
                resolve(res.state);
            }
        });

        this.on('error', err => {
            req.log('error', err.stack.replace(/\n/g, '\n  '));
            if (fulfilled) {
                req.log('fulfilled', 'Already fulfilled');
            } else {
                fulfilled = true;
                res.reset().set('content-type', 'text/plain').status(500).body(httpStatus[500]);
                req.log('fulfilled');
                if (rejectable) {
                    reject(err);
                } else {
                    resolve(res.state);
                }
            }
        });
    });

    // initialize variables
    const id = uuid();
    const hooks = {};
    const req = this;
    const res = new Response(this, keys.response);

    /**
     * Get the unique ID associated with this request.
     * @name Request#id
     * @type {string}
     * @readonly
     */
    Object.defineProperty(this, 'id', {
        configurable: false,
        enumerable: true,
        value: id
    });

    /**
     * Get the response object that is tied to this request.
     * @name Request#res
     * @type {Response}
     */
    Object.defineProperty(this, 'res', {
        configurable: false,
        enumerable: true,
        value: res
    });

    /**
     * Get the server instance that initialized this request.
     * @name Request#server
     * @type {SansServer}
     */
    Object.defineProperty(this, 'server', {
        enumerable: true,
        configurable: false,
        value: server
    });

    /**
     * Get the request URL which consists of the path and the query parameters.
     * @name Request#url
     * @type {string}
     * @readonly
     */
    Object.defineProperty(this, 'url', {
        configurable: false,
        enumerable: true,
        get: () => this.path + buildQueryString(this.query)
    });

    /**
     * Add a rejection handler to the request promise.
     * @name Request#catch
     * @param {Function} onRejected
     * @returns {Promise}
     */
    this.catch = onRejected => promise.catch(onRejected);

    /**
     * Produce a request log event.
     * @param {string} message
     * @param {...*} [args]
     * @returns {Request}
     * @fires Request#log
     */
    this.log = this.logger('sans-server', 'request', this);

    /**
     * Add request specific hooks
     * @param {string} type
     * @param {number} [weight=0]
     * @param {...Function} hook
     * @returns {Request}
     */
    this.hook = addHook.bind(this, hooks);

    /**
     * @name Request#hook.run
     * @param {Symbol} type
     * @param {function} [next]
     * @returns {Promise|undefined}
     */
    this.hook.reverse = (type, next) => runHooksMode(req, hooks, 'reverse', type, next);

    /**
     * @name Request#hook.run
     * @param {Symbol} type
     * @param {function} [next]
     * @returns {Promise|undefined}
     */
    this.hook.run = (type, next) => runHooksMode(req, hooks, 'run', type, next);

    /**
     * Add fulfillment or rejection handlers to the request promise.
     * @name Request#then
     * @param {Function} onFulfilled
     * @param {Function} [onRejected]
     * @returns {Promise}
     */
    this.then = (onFulfilled, onRejected) => promise.then(onFulfilled, onRejected);

    /**
     * The request body.
     * @name Request#body
     * @type {string|Object|Buffer|undefined}
     */

    /**
     * The request headers. This is an object that has lower-case keys and string values.
     * @name Request#headers
     * @type {Object<string,string>}
     */

    /**
     * This request method. The lower case equivalents of these value are acceptable but will be automatically lower-cased.
     * @name Request#method
     * @type {string} One of: 'GET', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'
     */

    /**
     * The request path, beginning with a '/'. Does not include domain or query string.
     * @name Request#path
     * @type {string}
     */

    /**
     * An object mapping query parameters by key.
     * @name Request#query
     * @type {object<string,string>}
     */

    // validate and normalize input
    Object.assign(this, config, normalize(req, config));

    // wait one tick for any event listeners to be added
    process.nextTick(() => {

        // run request hooks
        this.hook.run(keys.request)
            .then(() => {
                if (!res.sent) {
                    req.log('unhandled', 'request not handled');
                    if (res.state.statusCode === 0) {
                        res.sendStatus(404);
                    } else {
                        res.send();
                    }
                }
            })
            .catch(err => {
                this.emit('error', err)
            });
    });
}
function Request(server, keys, rejectable, config) {
    if (!config) config = {};
    if (typeof config !== 'object') config = { path: config };

    const promise = new Promise((resolve, reject) => {
        let fulfilled = false;

        this.on('res-complete', () => {
            if (fulfilled) {
                req.log('fulfilled', 'Already fulfilled');
            } else {
                fulfilled = true;
                req.log('fulfilled');
                resolve(res.state);
            }
        });

        this.on('error', err => {
            req.log('error', err.stack.replace(/\n/g, '\n  '));
            if (fulfilled) {
                req.log('fulfilled', 'Already fulfilled');
            } else {
                fulfilled = true;
                res.reset().set('content-type', 'text/plain').status(500).body(httpStatus[500]);
                req.log('fulfilled');
                if (rejectable) {
                    reject(err);
                } else {
                    resolve(res.state);
                }
            }
        });
    });

    // initialize variables
    const id = uuid();
    const hooks = {};
    const req = this;
    const res = new Response(this, keys.response);

    /**
     * Get the unique ID associated with this request.
     * @name Request#id
     * @type {string}
     * @readonly
     */
    Object.defineProperty(this, 'id', {
        configurable: false,
        enumerable: true,
        value: id
    });

    /**
     * Get the response object that is tied to this request.
     * @name Request#res
     * @type {Response}
     */
    Object.defineProperty(this, 'res', {
        configurable: false,
        enumerable: true,
        value: res
    });

    /**
     * Get the server instance that initialized this request.
     * @name Request#server
     * @type {SansServer}
     */
    Object.defineProperty(this, 'server', {
        enumerable: true,
        configurable: false,
        value: server
    });

    /**
     * Get the request URL which consists of the path and the query parameters.
     * @name Request#url
     * @type {string}
     * @readonly
     */
    Object.defineProperty(this, 'url', {
        configurable: false,
        enumerable: true,
        get: () => this.path + buildQueryString(this.query)
    });

    /**
     * Add a rejection handler to the request promise.
     * @name Request#catch
     * @param {Function} onRejected
     * @returns {Promise}
     */
    this.catch = onRejected => promise.catch(onRejected);

    /**
     * Produce a request log event.
     * @param {string} message
     * @param {...*} [args]
     * @returns {Request}
     * @fires Request#log
     */
    this.log = this.logger('sans-server', 'request', this);

    /**
     * Add request specific hooks
     * @param {string} type
     * @param {number} [weight=0]
     * @param {...Function} hook
     * @returns {Request}
     */
    this.hook = addHook.bind(this, hooks);

    /**
     * @name Request#hook.run
     * @param {Symbol} type
     * @param {function} [next]
     * @returns {Promise|undefined}
     */
    this.hook.reverse = (type, next) => runHooksMode(req, hooks, 'reverse', type, next);

    /**
     * @name Request#hook.run
     * @param {Symbol} type
     * @param {function} [next]
     * @returns {Promise|undefined}
     */
    this.hook.run = (type, next) => runHooksMode(req, hooks, 'run', type, next);

    /**
     * Add fulfillment or rejection handlers to the request promise.
     * @name Request#then
     * @param {Function} onFulfilled
     * @param {Function} [onRejected]
     * @returns {Promise}
     */
    this.then = (onFulfilled, onRejected) => promise.then(onFulfilled, onRejected);

    /**
     * The request body.
     * @name Request#body
     * @type {string|Object|Buffer|undefined}
     */

    /**
     * The request headers. This is an object that has lower-case keys and string values.
     * @name Request#headers
     * @type {Object<string,string>}
     */

    /**
     * This request method. The lower case equivalents of these value are acceptable but will be automatically lower-cased.
     * @name Request#method
     * @type {string} One of: 'GET', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'
     */

    /**
     * The request path, beginning with a '/'. Does not include domain or query string.
     * @name Request#path
     * @type {string}
     */

    /**
     * An object mapping query parameters by key.
     * @name Request#query
     * @type {object<string,string>}
     */

    // validate and normalize input
    Object.assign(this, config, normalize(req, config));

    // wait one tick for any event listeners to be added
    process.nextTick(() => {

        // run request hooks
        this.hook.run(keys.request)
            .then(() => {
                if (!res.sent) {
                    req.log('unhandled', 'request not handled');
                    if (res.state.statusCode === 0) {
                        res.sendStatus(404);
                    } else {
                        res.send();
                    }
                }
            })
            .catch(err => {
                this.emit('error', err)
            });
    });
}
function Request ( server , keys , rejectable , config ) { if ( ! config ) config = { } ; if ( typeof config !== 'object' ) config = { path : config } ; const promise = new Promise ( ( resolve , reject ) => { let fulfilled = false ; this . on ( 'res-complete' , ( ) => { if ( fulfilled ) { req . log ( 'fulfilled' , 'Already fulfilled' ) ; } else { fulfilled = true ; req . log ( 'fulfilled' ) ; resolve ( res . state ) ; } } ) ; this . on ( 'error' , err => { req . log ( 'error' , err . stack . replace ( / \n / g , '\n  ' ) ) ; if ( fulfilled ) { req . log ( 'fulfilled' , 'Already fulfilled' ) ; } else { fulfilled = true ; res . reset ( ) . set ( 'content-type' , 'text/plain' ) . status ( 500 ) . body ( httpStatus [ 500 ] ) ; req . log ( 'fulfilled' ) ; if ( rejectable ) { reject ( err ) ; } else { resolve ( res . state ) ; } } } ) ; } ) ; // initialize variables const id = uuid ( ) ; const hooks = { } ; const req = this ; const res = new Response ( this , keys . response ) ; /**
     * Get the unique ID associated with this request.
     * @name Request#id
     * @type {string}
     * @readonly
     */ Object . defineProperty ( this , 'id' , { configurable : false , enumerable : true , value : id } ) ; /**
     * Get the response object that is tied to this request.
     * @name Request#res
     * @type {Response}
     */ Object . defineProperty ( this , 'res' , { configurable : false , enumerable : true , value : res } ) ; /**
     * Get the server instance that initialized this request.
     * @name Request#server
     * @type {SansServer}
     */ Object . defineProperty ( this , 'server' , { enumerable : true , configurable : false , value : server } ) ; /**
     * Get the request URL which consists of the path and the query parameters.
     * @name Request#url
     * @type {string}
     * @readonly
     */ Object . defineProperty ( this , 'url' , { configurable : false , enumerable : true , get : ( ) => this . path + buildQueryString ( this . query ) } ) ; /**
     * Add a rejection handler to the request promise.
     * @name Request#catch
     * @param {Function} onRejected
     * @returns {Promise}
     */ this . catch = onRejected => promise . catch ( onRejected ) ; /**
     * Produce a request log event.
     * @param {string} message
     * @param {...*} [args]
     * @returns {Request}
     * @fires Request#log
     */ this . log = this . logger ( 'sans-server' , 'request' , this ) ; /**
     * Add request specific hooks
     * @param {string} type
     * @param {number} [weight=0]
     * @param {...Function} hook
     * @returns {Request}
     */ this . hook = addHook . bind ( this , hooks ) ; /**
     * @name Request#hook.run
     * @param {Symbol} type
     * @param {function} [next]
     * @returns {Promise|undefined}
     */ this . hook . reverse = ( type , next ) => runHooksMode ( req , hooks , 'reverse' , type , next ) ; /**
     * @name Request#hook.run
     * @param {Symbol} type
     * @param {function} [next]
     * @returns {Promise|undefined}
     */ this . hook . run = ( type , next ) => runHooksMode ( req , hooks , 'run' , type , next ) ; /**
     * Add fulfillment or rejection handlers to the request promise.
     * @name Request#then
     * @param {Function} onFulfilled
     * @param {Function} [onRejected]
     * @returns {Promise}
     */ this . then = ( onFulfilled , onRejected ) => promise . then ( onFulfilled , onRejected ) ; /**
     * The request body.
     * @name Request#body
     * @type {string|Object|Buffer|undefined}
     */ /**
     * The request headers. This is an object that has lower-case keys and string values.
     * @name Request#headers
     * @type {Object<string,string>}
     */ /**
     * This request method. The lower case equivalents of these value are acceptable but will be automatically lower-cased.
     * @name Request#method
     * @type {string} One of: 'GET', 'DELETE', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'
     */ /**
     * The request path, beginning with a '/'. Does not include domain or query string.
     * @name Request#path
     * @type {string}
     */ /**
     * An object mapping query parameters by key.
     * @name Request#query
     * @type {object<string,string>}
     */ // validate and normalize input Object . assign ( this , config , normalize ( req , config ) ) ; // wait one tick for any event listeners to be added process . nextTick ( ( ) => { // run request hooks this . hook . run ( keys . request ) . then ( ( ) => { if ( ! res . sent ) { req . log ( 'unhandled' , 'request not handled' ) ; if ( res . state . statusCode === 0 ) { res . sendStatus ( 404 ) ; } else { res . send ( ) ; } } } ) . catch ( err => { this . emit ( 'error' , err ) } ) ; } ) ; }
Generate a request instance.
@param {SansServer} server
@param {object} keys
@param {boolean} rejectable
@param {string|Object} [config] A string representing the path or a configuration representing all properties
to accompany the request.
@returns {Request}
@constructor
@augments {EventEmitter}
@augments {Promise}
Generate a request instance .