/QLfast

A TypeScript + Fastify + GraphQL template to plug and play, built with Docker. Batteries included.

Primary LanguageTypeScriptGNU General Public License v3.0GPL-3.0

QLfast

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.

Acknowledgements

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.

Running Locally

Requirements

The requirements for this template are simple:

  • Docker
  • Docker Compose

Additionally, to deploy to heroku you will need:

  • Heroku

Plug and Play

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].

Migrations

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.

Why this stack?

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

Caveats (or, may I say, Docker and Windows)

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 to 192.168.99.100:3000 and will not be found in localhost: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.

Docker Image

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.

When to Build

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).

Heroku Deployment

Automagic Deployment

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:

  1. Get your heroku API Key from your heroku dashboard and add it as a GitHub Secret to your repository with a key corresponding to HEROKU_API_KEY.
  2. 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 to APP_NAME.
  3. Make sure that your app has the heroku-postgresql addon provisioned. You can provision it from the dashboard or by running heroku addons:create heroku-postgresql:hobby-dev -a <appname> from your terminal, where <appname> corresponds to the name of your heroku app.
  4. Make sure that your app has the heroku-redis addon provisioned. You can provision it from the dashboard or by running heroku addons:create heroku-redis:hobby-dev -a <appname> from your terminal, where <appname> corresponds to the name of your heroku app.

So, to sum up, you should have the following GitHub Secrets in your repo:

  • HEROKU_API_KEY: your API key for heroku
  • APP_NAME: the name of your app in heroku

That's it! Your app should be now deploying automagically!

Manual Deployment

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.

Additional Features

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.