Genesis is a base Docker image that can be used to efficiently roll an application destined for deployment in a microservices achitecture.
- Usage
- Routes
- Database
- Application Architecture
- Support Endpoints
- Deployment Configuration
- Contributing
✅ environment variable based configurations ✅ liveness probe endpoint ✅ readiness probe endpoint ✅ prometheus metrics endpoint ✅ basic auth protection for metrics endpoint ✅ cross-origin-resource-sharing (cors) management ✅ gzip compression of responses ✅ header stripping ✅ server access logging ✅ out-of-the-box database connection ❌ logs streaming system for logs collators ❌ cross-site-request-forgery protection
To use Genesis in your project, create a Dockerfile
with the following contents:
FROM zephinzer/genesis:latest
COPY . /app
ENTRYPOINT ["npm", "start"]
In the same directory, create a ./routes
directory. This holds your custom routes. Each route file should export either an object or a middleware:
An object route should export a function that returns an object which has properties corresponding to the HTTP methods. For example:
module.exports = () => ({
get: (req, res) => { /* ... */ },
post: (req, res) => { /* ... */ },
put: (req, res) => { /* ... */ },
patch: (req, res) => { /* ... */ },
delete: (req, res) => { /* ... */ },
// ...
})
A middleware route should export a function that returns the Express middleware. For example:
module.exports = () =>
(req, res) => { /* ... */ };
To achieve a route structure of the following routes:
GET /object_a
GET /object_a/:id
POST /object_a/*
GET /
The directory structure would look like:
- {index}.js
- /object_a.js
- /object_a
- {_}id.js
- {star}.js
{_}
is mapped to ':'
, {index}
is mapped to ''
and {star}
is mapped to '*'
.
See https://github.com/zephinzer/express-diroutes for more information on the route generation from the directory structure.
Database migrations and seeds can be executed using the scripts found in ./provisioning
.
Create a new directory called db
and create a sub-directory in there named migrations
. New migrations can be placed in that directory and will automatically be run.
TODO: update after trying it out
Create a new directory called db
and create a sub-directory in there named seeds
. New seed files can be placed in that directory and will automatically be run.
TODO: update after trying it out
Basic Auth protected. This endpoint can be configured using an environment variable Exposes the Prometheus metrics.
This endpoint can be configured using an environment variable for customisation purposes
Exposes a health-check (livenessProbe
) for container orchestration systems to call.
Returns HTTP 200
with a JSON response body of "ok"
when all is good.
This endpoint can be configured using an environment variable for customisation purposes
Exposes a readiness-check (readinessProbe
) for container orchestration systems to call. We currently check for:
- database configuration error
- database client specification error
- database connection error
Returns HTTP 200
with a JSON response body of "ok"
when all is good.
Returns HTTP 500
with a JSON response body of all errors when something is wrong.
When this is defined, Cross-Origin-Resource-Sharing (CORS) is activated. If the value is an empty string, all origins will be allowed, otherwise, CORS is activated for the specified domains delimited by a comma.
When left undefined, Cross-Origin-Resource-Sharing is disabled.
Defaults to
undefined
.
When this is defined, basic auth will be applied to the following endpoints:
/metrics
The value for this environment variable should be an array of username:password
s separated by commas. An example:
BASIC_AUTH_USERS=user1:password1,user2:password2
The above will create two users, user1
and user2
, with their respective passwords.
Defaults to
undefined
.
Defines the client we should be connecting to the database with. This can be one of:
mysql
(MySQL)mysql2
(MySQL)sqlite3
(SQLite)pg
(PostgreSQL)mariasql
(MariaDB)oracle
(OracleDB)mssql
(MSSQL)
Defaults to
"mysql2"
.
Defines the maximum number of connections we should maintain with the database.
Defaults to
10
.
Defines the minimum number of connections we should maintain with the database.
Defaults to
2
.
Defines a connection URL.
Defaults to an object defining the database host (
DB_HOST
), database port (DB_PORT
), database schema (DB_SCHEMA
), database user (DB_USER
) and the password for the user (DB_PASSWORD
).
Defines the database host we should be connecting to. This is ignored if DB_CONNECTION_URL
is specified.
Defaults to
"localhost"
.
Defines the name for the database migration table we will be using.
Defaults to
"db_migrations_list"
.
Defines the password for the database user defined in the DB_USER
environment variable. This is ignored if DB_CONNECTION_URL
is specified.
Defaults to
"genesis"
.
Defines the database port we should be connecting to. This is ignored if DB_CONNECTION_URL
is specified.
Defaults to
3306
.
Defines the database schema we should be using. This is ignored if DB_CONNECTION_URL
is specified.
Defaults to
"genesis"
.
Defines the database user we should be using. This is ignored if DB_CONNECTION_URL
is specified.
Defaults to
"genesis"
.
Defines the endpoint for health checks to be done on.
Defaults to
/healthz
.
Defines the endpoint for metrics.
Defaults to
/metrics
.
Defines the environment we are running in.
Valid values are "development"
or "production"
. If it is neither, the server assumes "development"
Defaults to
"development"
.
Defines the port which the server should listen on.
Defaults to 4000.
Defines the endpoint for readiness checks to be done on.
Defaults to
/readyz
.
Specifies the realm for basic authentication.
Defaults to
"genesis"
.
We use ESLint to maintain code conventions and quality. To run the linter:
npm run eslint;
See the Travis CI script for more info.
Two types of tests are present in our tests. The first is unit tests which are most of tests you will see. The second is systems tests which simulates execution of the server and running queries against it - this is found in the server.test.js
.
We use mocha
, chai
, sinon
and supertest
to validate functional behaviour of the service.
To run the tests:
npm run mocha;
To run it in development which adds watching and allows for .only
and xit
keywords:
npm run mocha-watch;
See the Travis CI script for more info.
During development, we try to keep the feedback loop short, so we avoid running genesis in a Docker container.
Run the database alone using:
npm run db-development
The above command starts the database and builds the development image so that we can do a database migration and seed. If the database migration/seed files are changed, you will have to run the above command again to get the correct version of your database schema.
In development, we can use a live-reload tool such as nodemon
which watches for file changes and reloads the application when any changes are detected. This allows us to write code, save it and have our server reflect the newly acquired behaviour. To activate this, use:
npm run dev
The file ./.env
contains configurations that assume a database is running on the local computer. This database can be either a local MySQL instance, or you can spin it up using docker-compose
using npm run db-development
as shown above.
To create a development build, run:
npm run build -- development
To create a production build, run:
npm run build -- production
Building has no real use, we only use it in the Travis pipeline to push to DockerHub.
Start an issue so that everyone knows what you're working on. It'll suck if someone was doing the same thing you did and only one person's code will be merged in.
You can also assign the issue to yourself if you are taking up the work.
Fork this repository and make your changes in your master
branch. After making your changes:
- Update the
README.md
for the changes you have made - Add yourself as a contributor to the
package.json
file (yay) - Write/rewrite the tests for components you've changed - think of the tests as functional specifications so that if someone needs to see how something is used, they can refer to the tests.
- Add an appropriate version bump - use
[major version bump]
for a major version bump and[minor version bump]
for a minor one according to the SEMVER specification. Patch versions are automatically bumped if none of those tags are available.
Done making changes? Submit a Pull Request and let the Travis CI pipeline pass. On passing, your code will be reviewed using the Code Climate statistics as well as a human check to ensure leaness and maintainability.
For reading till the end, here's a potato.