How to build a simple REST server in node.js.
For this example I tried to avoid any frameworks targeting at a simple node.js code.
I did use however ES6 and promises.
If you want to skip my explanations, all the code is here: https://github.com/tan-tan-kanarek/node-rest-server-example
1. Main script – index.js
The main script defines a new RestServer with port to listen for HTTP requests and map of services (controllers), while the map keys will be used as service name in the REST requests and the map values are the classes that handle these requests.
Note that all services must extend RestController.
2. Server – RestServer
The server starts a new HTTP server listening on the port that supplied in the RestServer constructor.
Any request will be handled using RestServer.handler that parses the request (RestServer.parse) in order to get a RestRequest object.
If a valid RestRequest object returned, the handler will execute it and will send the response to the selected RestResponseSerializer.
Any unsuccessful parsing will result with sending the returned error to the RestResponseSerializer.
The RestResponseSerializer (more details bellow) will serialize the response to JSON or XML.
3. Request objects
I defined three types of requests.
RestSchemeRequest Parses the entire API and provides an XML descriptor that describe the entire API scheme, including controllers, actions, objects and enumerators. The scheme is auto-generated based on the code and configured services.
Note that the services, actions and data model objects are parsed using comments in the code, see example.
RestControllerRequest Accepts service (controller), action (method) and parameters (method arguments), as they parsed from the REST HTTP request.
The RestControllerRequest executes the method on a new instance of the service and returns the response or the error back to the server.
RestMultiRequest Handles a series of requests, that can save the HTTP round-trip in case you want to execute several requests together.
Note that this model force me to have flat list of services, it simplifies the routing URLs as well as the server code.
4. Services (controllers)
I created a simple users-service example with CRUD action (add, update, delete, get and search). The users-service is performing DB actions on a simple sqlite example file (run install.js to create it).
Normally I would have a single service for each data object while each service has CRUD actions for its data object, trying as much as I can to avoid nested objects, for example, if user has devices, I won’t add devices array on user object, I will prefer to create a new service called user-device that manages each user-device separately.
All service classes must extend RestController that translates the REST request to structured objects according to comments in the code.
5. Data model
An example user data model implemented in order to add, update, delete and search users.
All data-model objects must extend RestObject that translate plain JSON objects from the REST request to data-model objects, according to setters documentation in the code, see example.
6. Response serializer
Note that the response already contains errors and warnings in addition to the response content, so you don’t have to choose between response and error, you can return them both, that also means that the HTTP response code is always 200 OK, unless there is a true HTTP error, this way I distinguish between applicative errors and HTTP protocol errors.