UNPKG

sails

Version:

API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)

173 lines (139 loc) 4.76 kB
/** * Module dependencies. */ var util = require('util'); var _ = require('@sailshq/lodash'); var Transform = require('stream').Transform; var QS = require('querystring'); var detectVerb = require('../util/detect-verb'); /** * Originate a new client request instance and lob it at this Sails * app at the specified route `address`. * * Particularly useful for running unit/integration tests without * actually having to bind the HTTP and/or WebSocket servers to * a TCP port. * * @param {String} address * @param {Object} body * @param {Function} cb * @return {Stream.Readable} * * @api public */ module.exports = function request( /* address, body, cb */ ) { var sails = this; // // Body params may be passed in to DELETE, HEAD, and GET requests, // even though these types of requests don't normally contain a body. // (this method just serializes them as if they were sent in the querystring) // // Normalize usage var address = arguments[0]; var body; var cb; var method; var headers; var url; // Usage: // sails.request(opts, cb) // • opts.url // • opts.method // • opts.params // • opts.headers // // (`opts.url` is required) if (_.isObject(arguments[0]) && arguments[0].url) { url = detectVerb(arguments[0].url).original; method = arguments[0].method || detectVerb(arguments[0].url).verb; headers = arguments[0].headers || {}; body = arguments[0].params || arguments[0].data || {}; } // console.log('called sails.request() '); // console.log('headers: ',headers); // console.log('method: ',method); // Usage: // sails.request(address, [params], cb) if (arguments[2]) { cb = arguments[2]; body = arguments[1]; } if (_.isFunction(arguments[1])) { cb = arguments[1]; } else if (arguments[1]) { body = arguments[1]; } // If route has an HTTP verb (e.g. `get /foo/bar`, `put /bar/foo`, etc.) parse it out, // (unless method or url was explicitly defined) method = method || detectVerb(address).verb; method = method ? method.toUpperCase() : 'GET'; url = url || detectVerb(address).original; // Parse query string (`req.query`) var queryStringPos = url.indexOf('?'); // If this is a GET, HEAD, or DELETE request, treat the "body" // as parameters which should be serialized into the querystring. if (_.isObject(body) && _.contains(['GET', 'HEAD', 'DELETE'], method)) { var stringifiedParams = QS.stringify(body); if (queryStringPos === -1) { url += '?' + stringifiedParams; } else { url = url.substring(0, queryStringPos) + '?' + stringifiedParams; } } // Build HTTP Client Response stream var clientRes = new MockClientResponse(); clientRes.on('finish', function() { // console.log('clientRes finished. Headers:',clientRes.headers); // Only dump the buffer if a callback was supplied if (cb) { // Attempt to read the response buffer into a string try { clientRes.body = clientRes.read(); clientRes.body = clientRes.body.toString(); } catch (unusedErr) {} // Don't include body if it is empty. if (!clientRes.body) {delete clientRes.body;} // Now, if appropriate, parse the body as JSON. // (Attempt to parse as JSON if the content-type response header indicates it // would be a good idea -- and of course if there's a body.) if (!_.isUndefined(clientRes.body) && clientRes.headers['content-type'] === 'application/json') { clientRes.body = JSON.parse(clientRes.body); } // If status code is indicative of an error, send the // response body or status code as the first error argument. if (clientRes.statusCode < 200 || clientRes.statusCode >= 400) { var error = new Error(util.inspect(clientRes.body || clientRes.statusCode)); if (clientRes.body) {error.body = clientRes.body;} error.status = clientRes.statusCode; return cb(error); } else { return cb(undefined, clientRes, clientRes.body); } } }); clientRes.on('error', function(err) { err = err || new Error('Error on response stream'); if (cb) { return cb(err); } else { return clientRes.emit('error', err); } }); // To kick things off, pass `opts` (as req) and `res` to the Sails router sails.router.route({ method: method, url: url, body: body, headers: headers || {} }, { _clientRes: clientRes }); // Return clientRes stream return clientRes; }; function MockClientResponse() { Transform.call(this); } util.inherits(MockClientResponse, Transform); MockClientResponse.prototype._transform = function(chunk, encoding, next) { this.push(chunk); next(); };