# Basic Nestjs Application/API Boilerplate project with Git CI This project is based on the [Basic Docker Project with Git CI](https://git.price-hk.com/boilerplate-samples-projects/basic-docker-ci) project and include: 1. Node.js + Nestjs framework + Typescript + Swagger + JSON Logging (Shellscript + Winston) 1. This project is based on the new project generated by `nest new ` command (as of 2023-03-24) 1. Two dockerfile for production and development (which will be supported by `.gitlab-ci.yml`) 1. Dockerfile using multiple-stage builds 1. docker-compose setup for local development 1. Minimal API implementation (version, healthcheck) --- ## Local development using docker-compose and attach with VSCode ### Preparation *Assume you are using Linux (Mac or WSL2) and your login user id is 1000* 1. Clone the project 1. Prepare the `.env` (for docker-compose) and `.env-app` (for Node.js app) files 1. Refer to `sample.env-*` for the details 1. Create data folder (for vscode-server which will be running inside the container for VSCode) `mkdir -p ./data/vscode-server` 1. The VSCode extension and some required data will be saved in this persistence folder. 1. If you have started the service before making the directory (under your user account), you may get error when you attach VSCode. To resolve it, change the `data` and `vscode-server` folder ownership to you. 1. Build the image `docker-compose build` ### Start the environment as a dummy-daemon service *Assume you have installed docker extension in VSCode* `docker-compose up -d` ### Attach container with VSCode 1. Start the service (if not yet) 1. Start VSCode and locate Docker in the left tab panel, click the docker icon 1. Locate the running container of your application (e.g. `basic-nestjs-app`) 1. Right-click the container instance, select `Attach Visual Studio Code` 1. From the dropdown menu, select the instance again 1. A new VSCode Window will be shown if success 1. If it is the first time, please pick the working folder to `/home/node/app` ### Run the server application 1. In the VSCode terminal (within the container), type `yarn start` or `yarn start:dev` 1. To use the VSCode debugger, click the debug and launch the `Debug Nest Framework` (See `launch.json`) for details --- ## Databases This project requires connecting to the database (MySQL, MongoDB). There are docker-compose files contain the database service. ### Standalone DB service If you try this project with the local Node.js environment, you can use standalone database service which provided by the docker-compose.db.yml. It comes with these service: 1. MySQL/MariaDB server 1. Adminer - MySQL Web GUI Client 1. MonogoDB server 1. Monogo Express Web GUI Client Use the following command to manage the docker services/stack: ```bash # To start the service as daemon docker-compose -f docker-compose.db.yml up -d # To stop and down the service (and network resources) docker-compose -f docker-compose.db.yml down ``` #### Adminer Adminer is the Web GUI for MySQL/Mariadb. Once the docker-compose.db.yml is started, you may access it by: `http://localhost:33306` #### Mongo Express Mongo Express is the Web GUI for MongoDB. Once the docker-compose.db.yml is started, you may access it by: `http://localhost:32017` ### Troubleshooting #### Port binding issue In WSL2 environment, you may get the following error sometime: > Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:3306 -> 0.0.0.0:0: listen tcp 0.0.0.0:3306: bind: An attempt was made to access a socket in a way forbidden by its access permissions. First of all, you can check if there is stopped container that occupied the port, you can use the prune command to clean up the container: ```bash docker container prune ``` __NOTE:__ >In this project, we change the exposed ports to high-port, not low-port like 3306. Sometime, Windows firewall will block the port/port-range. It can be checked and add a rule via Powershell ```powershell # Check if 3306 is excluded: netsh int ipv4 show excludedportrange protocol=tcp # Add excluded range/port: (Need to run-as admin) netsh int ipv4 add excludedportrange protocol=tcp startport=3306 numberofports=1 # ``` --- ## Swagger The Nest Swagger framework is added into this project. For details, please see [Nestjs OpenAPI](https://docs.nestjs.com/openapi/introduction) documentation. When the is started and either `NODE_ENV` is not set to `production` OR `ENABLE_SWAGGER` is `true`, the swagger will be enabled. It can be access via URL: `/api`. For example: [http://localhost:3000/api](http://localhost:3000/api) ## About the Winston Logger and Price Service Core To use the Node.js Logger with Winston and output as a json format (required by Price's K8s best practice), please consider to use [Price Service Core](https://git.price-hk.com/price-core/service-core)'s Utility Service for logger. The Price Service Core has benn installed in this project. This is the command used: `yarn add --registry https://repo-manager.price-hk.com/repository/npm-group/ @price/service-core@0.4.0` And a wrapper class `WinstonLoggerService` (file `src/logger/winston.service.ts`) is created as well. Logger configration has also implemented in this project too. To use this, in your TS source code: 1. import the class. e.g.: `import { WinstonLoggerService } from './logger/winston.service';` 2. Set the context in constructor: ``` constructor(private logger: WinstonLoggerService) { this.logger.setContext(this.constructor.name); } ``` 3. Log as needed: `this.logger.debug("the message to log");` --- ## Working with the sample user-API (CURD) API-Doc: `/api` - Example: [http://localhost:3000/api](http://localhost:3000/api) Note: 1. The following use Linux cURL command to operate the API. 1. Header is provided. Especially for `POST` and `PATCH` ### Create User ```shell curl -X POST -H 'Content-Type: application/json' -d '{ "name": "Tester 1" }' 'http://localhost:3000/users' ``` ### List Users List users (with header outpu): ```shell curl -i 'http://localhost:3000/users' ``` Formatted result with JQ: ```shell curl -s 'http://localhost:3000/users' | jq ``` ### Get specific user ```shell curl -s 'http://localhost:3000/users/0' | jq ``` ### Update specific user ```shell curl -X PATCH -H 'Content-Type: application/json' -d '{ "name": "Tester 2" }' 'http://localhost:3000/users/1' ``` Note: Header must be provided. ### Delete specific user ```shell curl -X DELETE 'http://localhost:3000/users/1' ```