Project: API Web Server
I am currently building a simple Node.js based API web server. It’s primarily a proof-of-concept project that will be used when developing the API for another project. I have written similar servers for other projects in the past, this one should be cleaner and easier to use.
At the core of the server is the node http2 module. This provides the HTTP/2 web server, plus fall back to HTTP/1.1 support. HTTP/2 is the latest version of the hypertext transfer protocol and supports multiplexing data transfer connections, allowing multiple concurrent data streams. HTTP/1.1 serializes data transfer, meaning one stream has finish before another can begin. Below is the code that instantiates the http2 server
//Options for the http2 server const httpServerOptions = { key: fs.readFileSync(path.join(__dirname, 'keypath/key.pem')), cert: fs.readFileSync(path.join(__dirname, 'keypath/cert.pem')) }; var http2server; if (process.env.HTTP2_PLAIN) { console.log('Setting up HTTP2 Plain'); http2server = http2.raw.createServer({}, processRequest); } else { console.log('Setting up HTTP2 TLS'); http2server = http2.createServer(httpServerOptions, processRequest); }
processRequest is the callback function that handles the server requests, it takes two objects as parameters, request and response.
function processRequest(request, response) {
//process the request and provide a response ...
Since this is a simple server, it does not need to support many options. My current server implementation supports the following requirements:
- Passes GET and POST requests to the API endpoints
- API endpoints as modules
- Dynamically load modules during development
- Transfers html, js, css, and txt, files with correct mime types
- The allows it to be used as a basic file web server
- Display 404 when file or endpoint cannot be loaded
- Error logging
This is not a complete web server, but it could eventually be. A complete web server would support multiple HTTP response codes, have a plugin infrastructure, support large numbers of mime types, access logging, and numerous other features. At this point it is good for development and is easy to expand.
Since I have written similar servers in the past I looked at my previous code bases, it wasn’t pretty. I ended up finding duplicated code and signs of obvious confusion. When I coded the new server I made some similar mistakes, but upon reviewing the code I was able to move duplicated code into dedicated functions, then reworked the flow of the requests so that the main method was simpler. In the past I over complicated functions, stuffed too many actions into them. Simplify the methods increase the number of overall methods, but produced code that is easier to read and debug.
I added dedicated methods for displaying 404 messages, writing content and its mime type back to the requester, and wrote a method dedicated to handling POST and GET requests.
function processRequestMethod (request) { if (request.method === 'POST') { var data=''; request.on('data', function(chunk) { data += chunk; }); request.on('end', function() { return qs.parse(data); }); request.on('error', function(e) { console.error('ERROR with POST request '+e.message); }); } else { //Process as GET return qs.parse(url.parse(request.url).query); } }
My Next goal was to dynamically load API modules, to be continued in part 2.