From 1322cd2a0a499a516932f228c3370fcb6bcbc9b1 Mon Sep 17 00:00:00 2001 From: Michele Sessa Date: Wed, 22 Mar 2023 15:11:48 +0000 Subject: [PATCH] docs(crud-master): subject MVP all parts merged and complete implementation details are out of picture for now all names reviewed for consistency between subject and audit --- subjects/devops/crud-master/README.md | 162 +++++++++++++++++++++++--- 1 file changed, 145 insertions(+), 17 deletions(-) diff --git a/subjects/devops/crud-master/README.md b/subjects/devops/crud-master/README.md index c1ceea144..84090f164 100644 --- a/subjects/devops/crud-master/README.md +++ b/subjects/devops/crud-master/README.md @@ -32,26 +32,24 @@ We will couple it with Sequelize, an ORM which will abstract and simplify the in Here are the endpoints with the possible HTTP requests: -- `/movies`: GET, POST, DELETE -- `/movies/:id`: GET, PUT, DELETE +- `/api/movies`: GET, POST, DELETE +- `/api/movies/:id`: GET, PUT, DELETE Some details about each one of them: -- `GET /movies` retrieve all the movies. -- `GET /movies?title=[name]` retrieve all the movies with `name` in the title. -- `POST /movies` create a new product entry. -- `DELETE /movies` delete all movies in the database. +- `GET /api/movies` retrieve all the movies. +- `GET /api/movies?title=[name]` retrieve all the movies with `name` in the title. +- `POST /api/movies` create a new product entry. +- `DELETE /api/movies` delete all movies in the database. -- `GET /movies/:id` retrieve a single movie by `id`. -- `PUT /movies/:id` update a single movie by `id`. -- `DELETE /movies/:id` delete a single movie by `id`. +- `GET /api/movies/:id` retrieve a single movie by `id`. +- `PUT /api/movies/:id` update a single movie by `id`. +- `DELETE /api/movies/:id` delete a single movie by `id`. -- `GET /movies/available` retrieve all available the movies. +- `GET /api/movies/available` retrieve all available the movies. The API should work on `http://localhost:8080/`. -(TODO add a link on how to setup it?) - ##### Defining the Database For the database we will use PostgreSQL. @@ -63,20 +61,57 @@ Each movie will have the following columns: - `title`: the title of the movie. - `description`: the description of the movie. -(TODO add link on how to setup it?) - ##### Testing the Inventory API In order to test the correctness of your API you should use Postman (TODO add a link?). You could create one or more tests for every endpoint and then export the configuration so you will be able to reproduce the tests on different machines easily. #### API 2: Billing +##### Definition of the Inventory API + +This API will only receive messages through RabbitMQ. +The message it receives should be a stringified JSON object as in this example: + +```json +{ + "user_id": "3", + "number_of_items": "5", + "total_amount": "180" +} + +``` + +It will parse the message and create a new entry in the `orders` database. +It will also acknowledge the RabbitMQ queue that the message has been processed. +When the API is started it will take and process all messages present in the queue. + +> Take a look into `amqplib` npm package for an easy way to interface with RabbitMQ. + +##### Defining the Database + +For the database we will use PostgreSQL here as well. +The database will be called `orders`. + +Each order will have the following columns: + +- `id`: autogenerated unique identifier. +- `user_id`: the id of the user making the order. +- `number_of_items`: the number of items included in the order. +- `total_amount`: the total cost of the order. + +##### Testing the Billing API + +To test this API here are some steps: + +- Send POST orders to the API Gateway (you can use Postman for that). +- When the Billing API is running the orders should appear instantaneously in the `orders` database. +- When the Billing API is not running the queries to the API Gateway should still return success but the `orders` database won't be updated. +- When the Billing API is started again the unfulfilled messages should be processed and the `orders` database should be updated. + #### The API Gateway The Gateway will be the only service accessible by the user, it will take care of routing the requests to the appropriate API using the right protocol (it could be HTTP for API1 or RabbitMQ for API2). -The API Gateway should work on `http://localhost:3000/`. - ##### Interfacing with Inventory API The gateway will route all requests to `/api/movies` at the API1, without any need to check the information passed through it. @@ -91,6 +126,18 @@ The gateway will receive POST requests from `api/billing` and send a message usi The content of the message will be the POST request body stringified with `JSON.stringify`. The Gateway should be able to send messages to the API2 even if that API is not running. When the API2 will be started it should be able to process that message and send an acknowledgement back. +An example of POST request to `http://[API_GATEWAY_URL]:[API_GATEWAY_PORT]/api/billing/`: + +```json +{ + "user_id": "3", + "number_of_items": "5", + "total_amount": "180" +} +``` + +> Remember to setup `Content-Type: application/json` for the body of the request. + ##### Documenting the API Good documentation is a very critical feature of every API. By design the APIs are meant for others to use, so there have been very good efforts to create standard and easy to implement ways to document it. @@ -99,6 +146,87 @@ As an introduction to the art of great documentation you must create an OpenAPI #### Virtual Machines +##### General overview + +You will use DropBox and Vagrant to setup three different VMs in order to test the interactions and correctness of responses between your APIs infrastructure. + +Vagrant is an open-source software that helps you create and manage virtual machines. With Vagrant, you can create a development environment that is identical to your production environment, which makes it easier to develop, test, and deploy your applications. + +Your VMs will be structured as follow: + +- `gateway-vm`: This VM will only contain the `api-gateway`. +- `inventory-vm`: This VM will contain the `inventory-app` API and the database `movies`. +- `billing-vm`: This VM will contain the `billing-app` API, database `orders` and RabbitMQ. + +> Vagrant is designed for development and should not be used in production environments. + +##### Environment variables + +To simplify the building process it is a common practice to store useful variables in a `.env` file. It will make very easy to modify/update information like URLs, passwords, users and so on. + +Those variables will then be used by Vagrant and passed through the different APIs in order to centralize all the credentials. + +Your `.env` file should contain the following variables: + +```console +# postgres password +POSTGRES_PASSWORD=... +# postgres user for billing database +BILLING_DB_USER=... +# postgres password for billing database +BILLING_DB_PASSWORD=... +# postgres name for billing database +BILLING_DB_NAME=... +# postgres user for inventory database +INVENTORY_DB_USER=... +# postgres password for inventory database +INVENTORY_DB_PASSWORD=... +# postgres name for inventory database +INVENTORY_DB_NAME=... +# rabbitmq user +RABBITMQ_USER=... +# rabbitmq passowrd +RABBITMQ_PASSWORD=... +# rabbitmq port +RABBITMQ_PORT=5672 +# rabbitmq billing queue name +RABBITMQ_BILLING_QUEUE=billing_queue +# inventory api port +INV_APP_PORT=3001 +# apigateway api port +APIGATEWAY_PORT=3000 +``` + +> For the purpose of this exercise the `.env` file must be included in your repository, though usually in public and production projects the `.env` file is never included in repos to avoid sensitive data leaks. + +##### Configuration of the VMs + +- You will have a `Vagrantfile` which will create and start the three VMs. It will import the environment variables and pass them through each API. +- You will have a `script/` directory which will store all the scripts you may want to run in order to install the necessary tools on each VM. Those scripts may also be very useful for setting up the databases. + +Your configuration will work properly for the following commands (executed from the root of the project): + +- `vagrant up --provider virtualbox`: Starts all the VMs. +- `vagrant status`: Shows the status for all the VMs. +- `vagrant ssh `: Will let you access the VM through SSH. + +#### Manage Your Node.js applications with PM2 + +PM2 is a process manager for Node.js applications that makes it easy to manage and scale your application. +It is designed to keep your application running continuously, even in the event of an unexpected failure. + +PM2 can be used to start, stop, and list Node.js applications, as well as monitor their resource usage and log output. + +Additionally, PM2 provides a number of features for managing multiple applications, such as load balancing and automatic restarts. + +In our situation we will use it mainly to test resilience for messages sent to the Billing API when the API is not up and running. + +After entering in your VM via SSH you may run the following commands: + +- `sudo pm2 list`: List all running applications. +- `sudo pm2 stop `: Stop a specific application. +- `sudo pm2 start `: Start a specific application. + #### Overall file structure You can organize your internal file structure as you prefer. That said here is a common way to structure this kind of projects that may help you: @@ -133,7 +261,7 @@ You can organize your internal file structure as you prefer. That said here is a └── Vagrantfile ``` -You should be able to start the API Gateway and the two APIs by using the command `node server.js` inside their respective directories. +When testing and before to automate it through the VM build you should be able to start the API Gateway and the two APIs by using the command `node server.js` inside their respective directories. If you decide to use a different structure for your project remember you should be able to explain and justify your decision during the audit.