Fastify template built with Docker
and docker-compose
to plug and play. API-centric, includes a GraphQL server, a Redis instance and configures
the project with TypeScript.
Forked from the great Koa generator, oahu from @daleal.
Inspired from the awesome Full Stack React GraphQL TypeScript Tutorial from @benawad, which is published at GitHub.
The requirements for this template are simple:
Docker
Docker Compose
Additionally, to deploy to heroku
you will need:
Heroku
This repo comes with a docker-compose.yml
file to handle using a postgres
and a redis
image pulled from the web
and to use a .env
file for environment variables. As such, compose
requires a .env
file to function, so run:
cp .env.example .env
After that, configure the .env
file as you please and compose
is now ready to be used.
To get started quickly, build the image:
docker-compose build
Finally, start the server:
docker-compose up
Your app can now be found in localhost:3000
. From now on, every command regarding the app that should be run as [COMMAND]
will now be run as docker-compose run web [COMMAND]
.
A nifty TypeORM feature is the synchronization to the DB (while in development). With this, you don't need to bother
creating migrations while developing, as it will maintain the schema synchronized between the model and the DB.
As the synchronization is very risky in production, just remember to generate a migration when deploying to
Heroku to account for all the changes in the schema. For a cold start (first deploy) it's suggested to wipe out your
local DB (or create a new one, so the TypeORM-CLI creates the migrations considering an empty DB as the start point).
Make sure to configure the ormconfig.json
file with your development settings, and then proceed to generate a migration with docker-compose run web yarn run typeorm migration:generate -n InitialMigrationName
(yeah, that's a long one...)
You can test it locally by running docker-compose run web yarn run typeorm migration:run
.
For future schema changes, it's advisable to generate a migration for each major model modification.
As of August 2020, we are starting an API project that will definitely need some kind of scheduler and needs to communicate with mobile clients, so a low bandwidth usage is preferrable. GraphQL shines as a REST replacement for its ease of use, a single API endpoint, self documentation and prevention of both over- and under-fetching.
- Fastify: one of the fastest Node.js server frameworks
- fastify-gql: one of the fastest GraphQL server implementations (when using JIT compiling)
- TypeScript: provides type-safety and great IDE autocompletion for JS
- TypeORM: one of the best Typescript-first Node.js ORMs
- Type-GraphQL: great integration with TypeORM, they share a very similar syntax
- Redis: great in-memory storage, perfect for key expiration, scheduling, queues and message subscriptions
- Postgresql: strong choice for DBMS
If you are using Docker
on Linux or Docker
on MacOS, chances are your usage process has been almost flawless, and the instructions given in the tutorial worked at the first try. However, if you are using Docker Toolbox
on Windows or Docker for Windows
on Windows, things are different. Mainly, two things change:
- Due to the technology being run inside a Virtual Machine, instead of finding your app in
localhost:3000
, your app will be defaulted to192.168.99.100:3000
and will not be found inlocalhost:3000
. - Due to the database volume being mounted to a named volume created by the Virtual Machine, every Docker update will wipe your database clean. When using for development purposes, some simple seeds are enough to make this a no-problem. Keep an eye if that is your production environment, though, as data will be lost if you are not careful.
The image generated by docker-compose build
with the original repo has a size of ~507MB
, and contains a standard Fastify app using typescript
, postgresql
as the database, typeorm
as the ORM, type-graphql
as the GraphQL framework, fastify-graphql
as the GraphQL endpoint server, redis
as the in-memory store and node 14.8
as the JavaScript runtime.
The command docker-compose build
must be used only if there are changes in the package.json
: docker-compose build
will notice if either the package.json
or the yarn.lock
present any changes. If so, it will re-run yarn install
to update the image and tsc
to compile the TypeScript code
Notice that Docker
is smart and if you run docker-compose build
and the package.json
has not changed, Docker
will use cached layers to build the image, dramatically decreasing the amount of time wasted in your life (hopefully).
The template includes a GitHub Action to automagically deploy your app to heroku
! On every push to master
(or whenever a Pull Request gets merged into master
), the workflow will trigger and build, push and deploy your app to heroku
, including database migrations! For this magic to work, make sure to do the following stuff:
- Get your
heroku
API Key from yourheroku
dashboard and add it as a GitHub Secret to your repository with a key corresponding toHEROKU_API_KEY
. - Make sure to have a
heroku
app created. Get the app name and add it as a GitHub Secret to your repository with a key corresponding toAPP_NAME
. - Make sure that your app has the
heroku-postgresql
addon provisioned. You can provision it from the dashboard or by runningheroku addons:create heroku-postgresql:hobby-dev -a <appname>
from your terminal, where<appname>
corresponds to the name of yourheroku
app. - Make sure that your app has the
heroku-redis
addon provisioned. You can provision it from the dashboard or by runningheroku addons:create heroku-redis:hobby-dev -a <appname>
from your terminal, where<appname>
corresponds to the name of yourheroku
app.
So, to sum up, you should have the following GitHub Secrets in your repo:
HEROKU_API_KEY
: your API key forheroku
APP_NAME
: the name of your app inheroku
That's it! Your app should be now deploying automagically!
If you still want to deploy your app manually, you can use the Container Registry. To deploy to heroku
using Container Registry, make sure to be logged in to the platform (heroku login
). Then, log in to Container Registry:
heroku container:login
After that, create a new heroku
app:
heroku create
Don't forget to add the heroku-postgresql
addon to your heroku
app (when deploying to heroku
, only the Fastify app will be deployed, and the postgres
container used locally must be replaced with the heroku-postgresql
addon):
heroku addons:create heroku-postgresql:hobby-dev
As for the Redis instance, you should ensure the same is true:
heroku addons:create heroku-redis:hobby-dev
These commands will add the free basic heroku-postgresql
and heroku-redis
addons to your app (you can upgrade them later if you desire).
Next, build the image and push it to Container Registry:
heroku container:push web
Finally, release the image to your app:
heroku container:release web
Important Note: Once your app is created, to push new changes you only have to run heroku container:push web
and then heroku container:release web
.
To open the app in a browser, you can run heroku open
. You can also access directly using the app's URL.
The template also includes a Pull Request template. That means that every Pull Request's comment will get automagically filled with a default structure that can get altered.