17 Jan 2017 - by 'Maurits van der Schee'
I have written a simple REST API in Node.js. It includes routing a JSON REST request, converting it into SQL, executing it and giving a meaningful response. I tried to write the application as short as possible and came up with these 110 lines of code:
var http = require("http");
var mysql = require("mysql");
// connect to the mysql database
var pool = mysql.createPool({
connectionLimit: 100, //important
host: 'localhost',
user: 'my_username',
password: 'my_password',
database: 'my_database',
charset: 'utf8',
debug: false
});
// ensure request has database connection
var withDb = function (handler) {
return function (req, resp) {
pool.getConnection(function (err, connection) {
if (err) {
resp.writeHead(404)
resp.end(err);
return;
}
req.db = connection;
handler(req, resp);
});
}
};
// ensure request has (post) body
var withBody = function (handler) {
return function (req, resp) {
var input = "";
req.on("data", function (chunk) {
input += chunk;
});
req.on("end", function () {
req.body = input;
handler(req, resp);
});
}
};
// main web handler
var server = http.createServer(withDb(withBody(function (req, resp) {
// get the HTTP method, path and body of the request
var method = req.method;
var request = req.url.replace(/^[\/]+|[\/]+$/g, '').split('/');
try {
var input = JSON.parse(req.body);
} catch (e) {
var input = {};
}
// retrieve the table and key from the path
var table = req.db.escapeId(request.shift());
var key = req.db.escape(request.shift());
// create SQL based on HTTP method
var sql = '';
switch (req.method) {
case 'GET':
sql = "select * from " + table + (key ? " where id=" + key : '');
break;
case 'PUT':
sql = "update " + table + " set ? where id=" + key;
break;
case 'POST':
sql = "insert into " + table + " set ?";
break;
case 'DELETE':
sql = "delete " + table + " where id=" + key;
break;
}
// execute SQL statement
req.db.query(sql, input, function (err, result) {
// stop using mysql connection
req.db.release();
// return if SQL statement failed
if (err) {
resp.writeHead(404)
resp.end(err);
return;
}
// print results, insert id or affected row count
resp.writeHead(200, {
"Content-Type": "application/json"
})
if (req.method == 'GET') {
resp.end(JSON.stringify(result));
} else if (method == 'POST') {
resp.end(JSON.stringify(result.insertId));
} else {
resp.end(JSON.stringify(result.affectedRows));
}
});
})));
server.listen(8000);
The code is available on Github and is written to show you how simple it is to make a fully operational REST API in JavaScript.
Node.js applications are single threaded by default. With the "cluster" package, as shown in the code below (source), you can make Node.js use multiple cores.
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer(function(req, res) {
res.writeHead(200);
res.end('process ' + process.pid + ' says hello!');
}).listen(8000);
}
Note that using "cluster" has quite some overhead, so only do this when you have lots of cores and some cores of your machine are actually idle under full load.
To run the application you need to install Node.js (node) and Node Package Manager (npm). On Ubuntu Linux you can do this by running:
sudo apt-get install nodejs nodejs-legacy npm
To install the application's dependencies type:
npm install mysql
To run the application type:
node app.js
The URL you need to open in your browser is:
http://localhost:8000/{table-name}/{record-id}
NB: Don’t forget to adjust the database parameters in the above script!
Although the above code is not perfect it actually does do 3 important things:
One could thus say that the REST API is fully functional. You may run into missing features of the code, such as:
Don’t worry, all these features are available in php-crud-api, which you can get from Github. On the other hand, now that you have the essence of the application, you may also write your own!
PS: Liked this article? Please share it on Facebook, Twitter or LinkedIn.