I am writing an API and I am stuck at the point where I mix asynchronous and synchronous code depending on the incoming request, take a look at the examples below.
routes.js
module.exports = [ { method: 'GET', path: '/', controller: 'main', action: 'main', description: 'lists the API functionality', access: 'auth' }, { method: 'POST', path: '/users', controller: 'users', action: 'create', description: 'creates a new user', fields: { fullName: { format: { min: 2, max: 64, minWords: 2, disableDoubleSpaces: true }, description: 'the full name of the new user', examples: 'Thomas Richards, Richard Jones, Michael J. Fox, Mike Vercoelen, John Johnson' }, email: { format: { min: 2, max: 64, maxWords: 1, match: 'email' }, description: 'the email address of the new user', examples: ' mike@grubt.com , lilly@gmail.com , thomas.richards@mail.com , peter@mymail.com ' }, password: { format: { min: 2, max: 64 }, description: 'the password of the new user', examples: '123abcdfg, 7373kEjQjd, #8klKDNfk' } } } ];
the routes.js file is basically a very important part of the API, it checks incoming data, routes to the correct controller / action and determines if the method is public or requires authentication (basic auth).
api-server.js
var http = require('http'); var url = require('url'); var os = require('os'); var dns = require('dns'); var apiServer = module.exports; var routes = require('./routes.js'); // Routes file from above. var req, res, controller, action, serverInfo, httpServer; apiServer.start = function(){ prepare(function(){ httpServer = http.createServer(handleRequest).listen(3000); }); }; // // We need to do this function, we need the local ip address of the // server. We use this local ip address in logs (mongoDb) so we can // refer to the correct server. // function prepare(callback){ var serverName = os.hostname(); dns.lookup(serverName, function(error, address){ if(error){ throw error; } serverInfo = { name: serverName, address: address }; callback(); }); } function getRoute(){ // loops through routes array, and picks the correct one... } function getAuth(callback){ // parses headers, async authentication (mongoDB). } function getRequestData(callback){ // req.on('data') and req.on('end'), getting request data. } function parseRequestData(callback){ // parse request data at this point. } function validateRequestData(callback){ // loop through route fields (see routes.js) and validate this data with the ones // from the request. } function requireControllerAndCallAction(){ // do actual job. } function handleRequest(request, response){ req = request; res = response; req.route = getRoute(); // First step for a request, syncronous. if(req.route === false){ // 404... } // If in the routing schema access was "auth", // this route requires authentication, so do that... if(req.route.access === 'auth'){ getAuth(function(error, user){ if(error){ // 401 } else { req.user = user; } } } if(req.method === 'POST' || req.method === 'PUT'){ // Async functions. getRequestData(function(){ parseRequestData(function(){ validateRequestData(function(){ requireControllerAndCallAction(); }); }); }); } else { requireControllerAndCallAction(); } }
As you can see, some functions are asynchronous (getAuth, getRequestData), and some are synchronous (parseRequestData, validateRequestData).
Now here is what:
Request 1. comes with the POST method, url '/ users' and data:
- fullName = 'Rick'
- email: 'rick @'
- password: 'a'
So, we iterate over the API workflow:
get the current route (controller: users, action: create) see the second element of the array in routes.js
Get request data and callback: a. analyze data b. data validation
Now let's IMAGINE, the data check will take 5 seconds (which slows down, but only, for example), and during this check a new request arrives, the new request is not processed until the previous one is completed correctly?