私は API を書いていますが、着信要求に応じて非同期コードと同期コードを混在させているところで行き詰まりました。以下の例を見てください。
ルート.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'
}
}
}
];
routes.js ファイルは基本的に API の非常に重要な部分であり、受信データを検証し、正しいコントローラー/アクションにルーティングし、メソッドがパブリックかどうか、または認証 (基本認証) が必要かどうかを定義します。
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();
}
}
ご覧のとおり、一部の関数は非同期 (getAuth、getRequestData) であり、一部は同期 (parseRequestData、validateRequestData) です。
今ここにあります:
リクエスト 1. POST メソッド、url '/users'、およびデータが含まれています。
- fullName = 'リック'
- 電子メール: 'rick@'
- パスワード: 'a'
したがって、API のワークフローをループします。
現在のルートを取得します (コントローラー: ユーザー、アクション: 作成) routes.js の 2 番目の配列要素を参照してください
要求データを取得し、コールバックで次のことを行います。データを解析する b. データの検証
ここで想像してみましょう。データの検証には 5 秒かかります (これは遅れますが、例にすぎません)。その検証中に新しい要求が着信し、新しい要求は前の要求が完了するまで処理されません。