In this article I am describing a list of comprehensive steps, configurations and packages that I am using when creating
a NodeJS project that is developed in a Docker container. This is going to be a long path to completion, but at the end
of the rainbow I have a special tool that would make things fairly easier.
Setting the package
For the initial step we will create a basic configuration in the project directory. This includes a standard
package.json and a license.
You can find the MIT license which should be the template for your
LICENSE.md file. Don’t forget to change the “copyright holders” placeholder.
Configurations
We will add a set of configurations for environment variables, ESLint and Prettier. A Node-specific
.gitignore can be generated using Toptal’s tool.
Finally, we are going to create a standard folder structure for our work:
OpenAPI
OpenAPI represents the current de-facto standard for specifying a HTTP APIs,
making it both human and machine readable, with the advantages of verification, automation and communication of common
interfaces inside a project and between projects. I tend to use OpenAPIs as a request response validation tool, but it
can be used even as the first step of any API, at the conceptual phase. We start our project with a basic,
undifferentiated spec.
Docker
Increasing both development speed and ease, having a Docker-capable project from the start can improve the quality of
your work later, so we create a set of files that are sufficient for a small backend server. At any time, the backend
can be extended by adding external loggin, API gateways using Kong or databases, making the
project almost ready for deployment.
We need to make an actual environment variables file (starting with the given example). Building an image will be
possible at the end of the setup.
Base packages
At this point we will be installing a number of packages that form the core of our application. In order, they are:
Docker production secret management with docker-secret
You can see other potential packages (depending om the actual usecase) at the end of the article.
We initialize a git repository in order to set up the next package.
We shouldn’t forget to add husky in order to use git hooks that assure our code
quality, such as consistent formatting, respecting ESLint rules and running security checks. Tests are also welcome.
Base source code
It is now finally time to write the base source code. The following snippets will take advantage or complete all the
previous steps.
Utilities
First we get some utilities set up, like config.mjs and logger.mjs for reading configurations from environment
variables and logging events respecively.
Both ServerError.mjs and middleware.mjs refer to error handling, either being a base error class or a set of
Express middleware functions to inject directly into our pipeline.
Finally, some short utility functions to ease the use of fetch calls.
Main modules
Before we actually start the app, we will set up a healthcheck script that was previously referenced in out Dockerfile.
Its use might not be obvious in the normal case, but it manages to answer status requests and verify that the state of
our server is still running.
In our main script, we create an Express app and start an HTTP server running that app.
Our app uses the common middleware for HTTP headers, parsing request bodies into json and request logging. We further
connect the OpenAPIValidator running with the spec defined above and use a set of routes defined in our router module.
Finally, we declare an endpoint that answers the liveliness probe and catch all other async errors.
For the routes themselves, we just introduce a standard /hello route to test in the most general way that a GET
request works properly.
Final details
At this point, you can create the initial commit (or use git cz if you’ve read my previous
article and now use Commitizen) and start working on your real work.
I am aware that the above seem to be a numerous set of steps that might not alll be necessary, especially for a small
scale microservice. The truth is that this article has the purpose of putting all those step in a logical order, exactly
because it is a complex process. However, I can try to better help you right now. You can use my own NPM package,
create-edo-app that helps starting this project only using
an npx call. It is a work in progress, so I recommend careful consideration when using my boilerplate, templetized
package, but I trust that at some point in the future I will start all my Express servers using this one.