Live Demo Here!!
This small project implements some of the best practices for developing REST APIs, such as:
Note: Some points are just recommendations for scaling and were not implemented here because of the time available. those are going to be marked with *
or as a Note
This project runs on docker
and docker-compose
locally. We need some environment variables which will be placed in .env
for backend
folder and .env.local
for frontend, you can find those in each folder.
docker-compose build
docker-compose up
After docker services are running cd ./backend && npm run db:reset
this will create database and run all migrations and seeds
npm run db:migrate
npm run db:seeds
npm run test
- Pick
calculator-api.postman_collection.json
and import it in Postman
- Fronted: React (using server side rendering with Next.js), tailwind, axios, Typescript
- Backend: Typescript, Express, jsonwebtoken, sequelize, morgan
-
The project already has a simple architecture and folder organization based on Clean Architecture and Domain Driven Design
application
,domain
, andinfrastructure
. All use cases and business logic are underdomain\services
anddomain\models
where other code likeapplication
andinfrastructure
could be replaced as dependencies if it's needed since using Dependency injection to inject repository to services and services to application controllers. -
Dependency Injection
-
Factory Method
-
In order to deploy this to AWS the project is using a GitHub Actions workflow that builds a docker image and pushes it to ECR and later is deployed to ECS using a task definition service
.github/workflows/aws-deploy
, since the frontend use case is using NextJs, the deploy is being executed with Vercel Deployments. -
Workflow action for build and test on PR
-
The backend API is secured by JWT token, each time a user
sign-in/sign-up
a token is returned which should be sent back in the requestAuthorization
header in order to access API resources. -
The frontend App sends a
Authorization: Bearer jwt-token
on each request. Relay on Next in order to secure the token on each request. Creating a signed and encrypted cookie with 32 length password undernext/api
which hold the jwt-token using iron-session.
Note Integrate with SonarQube and OWASP dependency check
-
Unit Testing for services and repository
-
Also a simple Postman collection file is added to the project.
Note Cypress E2E testing React Testing library for testing React comppmemt
Note *Define test coverage at least 75%
Note
- implementation handles testing using integration testing making sure the server responds with the correct HTTP code and data using supertest and inmemory postgres data base. Create a stub database for testing in order to have a separate environment
-
For this case I wrote a simple error handler system based on classes
domain/entities/errors
and relaying on expressexpress-async-errors
so that I can throw errors direct fromcontroller
,repositories
orservices
using async/await when is needed -
CustomError abstract class used as a template for mapping error object structure response
Note
- Other tool that could help with this in a simple way https://hapi.dev/module/boom/api/?v=10.0.1
-
To validate input data to route controllers, a validator middleware was added relaying on express validator to validate body payload.
-
Having a validator in
infrastructure
, so it could be reusable by multiple controllers if needed.
I consider resiliency API an important topic since production API should be ready and online but we have to make sure for this simple case to create a separate endpoint to check the health and return 200 if API is up and running.
/health
endpoint in order to check when API is available which is used by the AWS cluster service health check.
Note
- Graceful shutdowns, would ensure processes or connections get closed if the apps crash, Useful simple lib:https://github.com/hunterloftis/stoppable
- For this example, we use Morgan for service http logs and console.log for server errors and returning a friendly message for the client user.
Note
- We could update the implementation with something more robust like Winston with AWS Cloud Watch Integration
- Some utilities used throughout the project are placed on shared locations so it would be accessible by another part of the API in the case is needed under the
infrastructure
folder
- As for how to use the API, I added a Postman collection file with the API's use cases so the user can get familiar with how to request and what the endpoints are expecting.
Genaral Notes
- Agragate Swagger API Documentations
- Storybooks for React component documentations
- In order to improve operation transactions could be added SQL transactions. so if any issue happens in the process of debit/credit we could easily rollback