BVB Source Codes

parse-server Show PromiseRouter.js Source code

Return Download parse-server: download PromiseRouter.js Source code - Download parse-server Source code - Type:.js
  1. // A router that is based on promises rather than req/res/next.
  2. // This is intended to replace the use of express.Router to handle
  3. // subsections of the API surface.
  4. // This will make it easier to have methods like 'batch' that
  5. // themselves use our routing information, without disturbing express
  6. // components that external developers may be modifying.
  7.  
  8. import Parse     from 'parse/node';
  9. import express   from 'express';
  10. import log       from './logger';
  11. import {inspect} from 'util';
  12. const Layer = require('express/lib/router/layer');
  13.  
  14. function validateParameter(key, value) {
  15.   if (key == 'className') {
  16.     if (value.match(/_?[A-Za-z][A-Za-z_0-9]*/)) {
  17.       return value;
  18.     }
  19.   } else if (key == 'objectId') {
  20.     if (value.match(/[A-Za-z0-9]+/)) {
  21.       return value;
  22.     }
  23.   } else {
  24.     return value;
  25.   }
  26. }
  27.  
  28.  
  29. export default class PromiseRouter {
  30.   // Each entry should be an object with:
  31.   // path: the path to route, in express format
  32.   // method: the HTTP method that this route handles.
  33.   //   Must be one of: POST, GET, PUT, DELETE
  34.   // handler: a function that takes request, and returns a promise.
  35.   //   Successful handlers should resolve to an object with fields:
  36.   //     status: optional. the http status code. defaults to 200
  37.   //     response: a json object with the content of the response
  38.   //     location: optional. a location header
  39.   constructor(routes = [], appId) {
  40.     this.routes = routes;
  41.     this.appId = appId;
  42.     this.mountRoutes();
  43.   }
  44.  
  45.   // Leave the opportunity to
  46.   // subclasses to mount their routes by overriding
  47.   mountRoutes() {}
  48.  
  49.   // Merge the routes into this one
  50.   merge(router) {
  51.     for (var route of router.routes) {
  52.       this.routes.push(route);
  53.     }
  54.   }
  55.  
  56.   route(method, path, ...handlers) {
  57.     switch(method) {
  58.     case 'POST':
  59.     case 'GET':
  60.     case 'PUT':
  61.     case 'DELETE':
  62.       break;
  63.     default:
  64.       throw 'cannot route method: ' + method;
  65.     }
  66.  
  67.     let handler = handlers[0];
  68.  
  69.     if (handlers.length > 1) {
  70.       handler = function(req) {
  71.         return handlers.reduce((promise, handler) => {
  72.           return promise.then(() => {
  73.             return handler(req);
  74.           });
  75.         }, Promise.resolve());
  76.       }
  77.     }
  78.  
  79.     this.routes.push({
  80.       path: path,
  81.       method: method,
  82.       handler: handler,
  83.       layer: new Layer(path, null, handler)
  84.     });
  85.   }
  86.  
  87.   // Returns an object with:
  88.   //   handler: the handler that should deal with this request
  89.   //   params: any :-params that got parsed from the path
  90.   // Returns undefined if there is no match.
  91.   match(method, path) {
  92.     for (var route of this.routes) {
  93.       if (route.method != method) {
  94.         continue;
  95.       }
  96.       const layer = route.layer || new Layer(route.path, null, route.handler);
  97.       const match = layer.match(path);
  98.       if (match) {
  99.         const params = layer.params;
  100.         Object.keys(params).forEach((key) => {
  101.           params[key] = validateParameter(key, params[key]);
  102.         });
  103.         return {params: params, handler: route.handler};
  104.       }
  105.     }
  106.   }
  107.  
  108.   // Mount the routes on this router onto an express app (or express router)
  109.   mountOnto(expressApp) {
  110.     this.routes.forEach((route) => {
  111.       const method = route.method.toLowerCase();
  112.       const handler = makeExpressHandler(this.appId, route.handler);
  113.       expressApp[method].call(expressApp, route.path, handler);
  114.     });
  115.     return expressApp;
  116.   }
  117.  
  118.   expressRouter() {
  119.     return this.mountOnto(express.Router());
  120.   }
  121.  
  122.   tryRouteRequest(method, path, request) {
  123.     var match = this.match(method, path);
  124.     if (!match) {
  125.       throw new Parse.Error(
  126.         Parse.Error.INVALID_JSON,
  127.         'cannot route ' + method + ' ' + path);
  128.     }
  129.     request.params = match.params;
  130.     return new Promise((resolve, reject) => {
  131.       match.handler(request).then(resolve, reject);
  132.     });
  133.   }
  134. }
  135.  
  136. // A helper function to make an express handler out of a a promise
  137. // handler.
  138. // Express handlers should never throw; if a promise handler throws we
  139. // just treat it like it resolved to an error.
  140. function makeExpressHandler(appId, promiseHandler) {
  141.   return function(req, res, next) {
  142.     try {
  143.       const url = maskSensitiveUrl(req);
  144.       const body = Object.assign({}, req.body);
  145.       const stringifiedBody = JSON.stringify(body, null, 2);
  146.       log.verbose(`REQUEST for [${req.method}] ${url}: ${stringifiedBody}`, {
  147.         method: req.method,
  148.         url: url,
  149.         headers: req.headers,
  150.         body: body
  151.       });
  152.       promiseHandler(req).then((result) => {
  153.         if (!result.response && !result.location && !result.text) {
  154.           log.error('the handler did not include a "response" or a "location" field');
  155.           throw 'control should not get here';
  156.         }
  157.  
  158.         const stringifiedResponse = JSON.stringify(result, null, 2);
  159.         log.verbose(
  160.           `RESPONSE from [${req.method}] ${url}: ${stringifiedResponse}`,
  161.           {result: result}
  162.         );
  163.  
  164.         var status = result.status || 200;
  165.         res.status(status);
  166.  
  167.         if (result.text) {
  168.           res.send(result.text);
  169.           return;
  170.         }
  171.  
  172.         if (result.location) {
  173.           res.set('Location', result.location);
  174.           // Override the default expressjs response
  175.           // as it double encodes %encoded chars in URL
  176.           if (!result.response) {
  177.             res.send('Found. Redirecting to ' + result.location);
  178.             return;
  179.           }
  180.         }
  181.         if (result.headers) {
  182.           Object.keys(result.headers).forEach((header) => {
  183.             res.set(header, result.headers[header]);
  184.           })
  185.         }
  186.         res.json(result.response);
  187.       }, (e) => {
  188.         log.error(`Error generating response. ${inspect(e)}`, {error: e});
  189.         next(e);
  190.       });
  191.     } catch (e) {
  192.       log.error(`Error handling request: ${inspect(e)}`, {error: e});
  193.       next(e);
  194.     }
  195.   }
  196. }
  197.  
  198.  
  199. function maskSensitiveUrl(req) {
  200.   let maskUrl = req.originalUrl.toString();
  201.   const shouldMaskUrl = req.method === 'GET' && req.originalUrl.includes('/login')
  202.                       && !req.originalUrl.includes('classes');
  203.   if (shouldMaskUrl) {
  204.     maskUrl = log.maskSensitiveUrl(maskUrl);
  205.   }
  206.   return maskUrl;
  207. }
  208.  
downloadPromiseRouter.js Source code - Download parse-server Source code
Related Source Codes/Software:
react-boilerplate - 2017-06-07
webtorrent - Streaming torrent client for the web ... 2017-06-06
machine-learning-for-software-engineers - A complete daily plan for studying to become a mac... 2017-06-06
upterm - A terminal emulator for the 21st century. 2017-06-06
lottie-android - Render After Effects animations natively on Androi... 2017-06-07
AsyncDisplayKit - Smooth asynchronous user interfaces for iOS apps. ... 2017-06-07
ionicons - The premium icon font for Ionic ... 2017-06-07
storybook - 2017-06-07
prettier - Prettier is an opinionated JavaScript formatter. ... 2017-06-08
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top