The very first step you must take in this project is simple:
-
Find all occurrences of
my-nest-rest-starter
-
Replace them with your project's name composed of characters matching the regex:
/^[(a-z\-){+}]$/
(at least one character, all being lower case or hyphen)
-
Then go to your project's GitHub repository
- Under
Settings
, selectEnvironments
and create new environments- To run the project's pipeline without any adaption we recommend
test
,staging
and,production
being created; With these exact names!
- To run the project's pipeline without any adaption we recommend
- Under
Settings
, selectSecrets > Actions
and create twoEnvironment
per each of the previously added environments:JWT_PRIVATE_KEY_BASE64
JWT_PUBLIC_KEY_BASE64
- You can leave them as blank strings for now;
- We will teach you how to fill these in a later section: generating pub/priv keys
- If you decide to keep on using
Dependabot
, non secret-environment variables which are not hard-coded on workflow files, as well as secret variables (environment, repository, and/or organization), must also be added toSecrets > Actions > Dependabot
, otherwise theDependabot
Pull Requests will constantly fail. For the initial setup only the two variables above, need to be added toDependabot Secrets
.
- Under
Wether you are on MacOS or Linux, we recommend that you install the following tooling:
-
oh-my-zsh with your favorite plugins
# We personally enjoy using at least these: plugins=( git zsh-autosuggestions zsh-completions zsh-syntax-highlighting )
-
Homebrew and remember to follow the instructions at the end of the program output.
- Installing Homebrew and installing casks (programs) managed by Homebrew often
require exporting environment variables, adding scripts, or similar in your
.zshrc
,.bashrc
or other profile files. - Always check the program output for further instructions!
brew install openssl brew install direnv # Directory Environment requires additional setup in your rc file brew install libpq # Node Version Manager requires additional setup in your rc file brew install nvm # Installs the latest Node LTS that satisfies the `.nvmrc` file given by the project nvm use
- Installing Homebrew and installing casks (programs) managed by Homebrew often
require exporting environment variables, adding scripts, or similar in your
If you installed nvm
and libpq
you do not need anything other than Docker
and
Docker-Compose
.
-
- These are installed seperately if you are using a Linux distro;
-
NodeJS matching the project's version
- If you use nvm and
zsh
as a shell you can automate process of installing and/or setting the properNode
for any project which provides.nvmrc
, when switching to it's directory or a child of it. Just add this block to your.zshrc
# place this after nvm initialization! autoload -Uz add-zsh-hook load-nvmrc() { if [[ -f .nvmrc && -r .nvmrc ]]; then nvm use elif [[ $(nvm version) != $(nvm version default) ]]; then echo "Reverting to nvm default version" nvm use default fi } add-zsh-hook chpwd load-nvmrc load-nvmrc
- If you use nvm and
-
Postgres or compatible binaries
When using docker, all of the project's 'npm
commands can also be performed using
./scripts/npm
(e.g.: ./scripts/npm install
). This script allows you to run the same
commands inside the same environment and versions than the service, without relying on
what is installed on the host and without decorating fancy docker/docker-compose exec
commands.
We use NPM and we disallow any attempt to use Yarn or PNPM; We recognize that Yarn and especially PNPM are faster than NPM; But GitHub Actions PNPM support is still somewhat limited, it is also harder to find professional grade examples using these managers, when it comes to private packaging, CI/CD, among others.
npm install
- Create a
.env
file from the template.env.template
file.
cp .env.template .env
- Fill in any unfilled variables.
- See next section for
JWT_PUBLIC_KEY_BASE64
andJWT_PRIVATE_KEY_BASE64
- See next section for
These variables are key to the application proper operation. Without these
environment variables, the application runtime
will fail and e2e
will certainly
pick that up!
Run this command:
./scripts/generate-jwt-keys
Copy the output of that command and add it to your .env
file. It looks something
like this:
To setup the JWT keys, please add the following values to your .env file:
JWT_PUBLIC_KEY_BASE64="(long base64 content)"
JWT_PRIVATE_KEY_BASE64="(long base64 content)"
The keys will be generated on .local
folder, which is ignored by .gitignore
.
mkdir ./local
ssh-keygen -t rsa -b 2048 -m PEM -f ./local/jwtRS256.key -N ""
openssl rsa -in jwtRS256.key -pubout -outform PEM -out ./local/jwtRS256.key.pub
base64 -i ./local/jwtRS256.key
base64 -i ./local/jwtRS256.key.pub
Must enter the base64 of the key files in .env
:
# Ensure that you insert both outputs in your environment without any newlines
JWT_PUBLIC_KEY_BASE64="BASE64_OF_JWT_PUBLIC_KEY"
JWT_PRIVATE_KEY_BASE64="BASE64_OF_JWT_PRIVATE_KEY"
We can run the project with or without docker.
To run the server without Docker we need this pre-requisite:
- Postgres server running with applied migrations (we only apply and synch automatically in E2E tests)
Commands:
# Apply the migrations if needed
npm run typeorm:migration:run
# development
npm run start
# watch mode
npm run start:dev
# production mode
npm run start:prod
# build image
docker build -t my-nest-rest-starter .
# run container from image
docker run -p 3000:3000 --volume 'pwd':/usr/src/app --network --env-file .env my-nest-rest-starter
# run using docker compose
docker compose up
# unit tests (with or without JEST coverage)
npm run test
npm run test:cov
# integration
# not available yet
# e2e tests
npm run test:e2e
# Example using docker (all remaining commands can also be used in the same way)
docker-compose exec app npm run typeorm:migration:run
# Directly on host machine
# Apply migrations on local machine
npm run typeorm:migration:run
# Revert the previous migration applied on your local machine
npm run typeorm:migration:revert
# Generate migration file from changes applied to the entities. Be aware that
# the generated file may need some fine tuning. Always verify the generated
# migration instructions as they can easily compromise dev, qa and production
# databases when applied.
npm run typeorm:migration:generate --name='name'
# Create an empty migration file
npm run typeorm:migration:create --name'name'
# Write in the console the pending changes
npm run typeorm:migration:log
# Write in the console the pending migrations to be applied
npm run typeorm:migration:show
# Drop database, deletes all tables
npm run schema:drop
# Sync entities with database, creates, and updates database tables
# We do this automatically on application start-up.
npm run schema:sync
Any environment variable which is not a secret or is just a placeholder for test should be added to any workflows (.github/workflows/*.yml
files) as the project grows.
- See tests-workflow.yml example;
- Note that some of the environment variables which are hard-coded here are typically secret
- But since these are used only during the
testing-workflow
and do not communicate with real systems, and instead communicate with transient dockerized containers (running as local processes on the host where the workflow is executing), they do not need to be treated as such!
Any environment variable considered secret should be added as Environment, Repository or Organization Secret
on GitHub. Examples include API KEYS, Database Connection Credentials, Public/Private Key pairs like the ones we created earlier (JWT_PRIVATE_KEY_BASE64
/JWT_PUBLIC_KEY_BASE64
)
- See build-workflow example, which accesses the
staging
environment variables to load them into the workflow. - You can find the secrets dashboard at
(repository) Settings > Secrets > Actions
- Any secret environment variable required to run the
testing
workflows, which is not hardcoded on the workflow itself should also be added a Dependabot Secrets. By default, pull requests created by Dependabot do not have access to any GitHub Secrets (for security purposes). Without this effort, all Dependabot pull requests will fail on the testing step!
# You must provide the correct relative or absolute path to -f option
# When prompted for a password, type in the value of DATABASE_PASSWORD of `.env`
export NODE_ENV=dev;
npm run typeorm schema:drop;
psql --dbname=$DB_NAME --username=$DB_USER --host=$DB_HOST --port=$DB_PORT -f ~/Downloads/example-dump.sql;
The baseline for this project was taken from MonstraLab OSS template
To view sample implementations based on this starter kit, please visit the nestjs-sample-solutions repository.
One of our main principals has been to keep the starter kit as lightweight as possible. With that in mind, here are some of the features that we have added in this starter kit.
Feature | Info | Progress |
---|---|---|
Authentication | JWT | Done |
Authorization | RBAC (Role based) | Done |
ORM Integration | TypeORM | Done |
DB Migrations | TypeORM | Done |
Logging | winston | Done |
Request Validation | class-validator | Done |
Pagination | SQL offset & limit | Done |
Docker Ready | Dockerfile | Done |
Auto-generated OpenAPI | - | Done |
Auto-generated ChangeLog | - | WIP |
Apart from these features above, our start-kit comes loaded with a bunch of minor awesomeness like prettier integration, commit-linting husky hooks, package import sorting, docker-compose for database dependencies, etc.