Skip to main content
Development of a React web application and an API with a microservices architecture

Development of a React web application and an API with a microservices architecture

Project Overview
#

I completed this project during my second year of computer science studies. The goal was to apply our knowledge of frontend and backend web development. The frontend constraints required creating a Single-Page Application (SPA) using React. For the backend, we had to develop an API that relied on external APIs and a user management system, all using a microservices architecture.

For this project, we decided our application would focus on a collectible card game, drawing partial inspiration from the features of the Pokémon TCG Pocket app.

Our team consisted of five members, and I had the opportunity to take on the role of project manager. In addition to development, I was responsible for assigning tasks and managing deliverables and deadlines.

Technical Challenges
#

Application Architecture
#

The first key aspect of this project was the microservices organization. The goal was to divide the application into a set of small, specialized services. Each service is independent and communicates with others through an interface—in our case, a REST API. This architecture offers several advantages. First, it allows each service to be developed independently, so modifying one does not require changes to the entire system. Another benefit is that the entire backend (data processing, user management, etc.) is separated from the frontend web application. This makes it easy to imagine developing an Android app, for example, that interacts with the same backend.

Application Architecture Diagram
Diagram of the application’s overall architecture with the different services.

Frontend
#

The web application was built using React and standard tools like Vite for building and React Router for site routing. We also used the Radix UI component library to speed up interface development. The main challenge in this part was managing the numerous API calls with a reactive interface, which required careful use of Hooks.

Backend
#

Each backend service follows an architecture similar to the MVC model. First, each service consists of models that describe the data type of each field in a data object. Then, there are DAOs (Data Access Objects), which separate database queries from the rest of the code. This makes it easy to change the data storage medium, only the DAO needs to be rewritten. Next are the controllers, which define the API actions and interface with the DAO, along with additional tasks like cache management and authentication verification. Finally, there are the routes, which adhere to the uniform interface of a REST API.

All services were developed using the lightweight framework Express.js. Special attention was given to API documentation, which is automatically generated from routes and comments using Swagger. Additionally, for all components (routes, controllers, models, DAOs), we wrote comprehensive unit tests to validate the overall functionality of the API. To achieve this, we set up a “stub” which is an API that returns static responses. This allowed us to test interactions between services and also sped up interface development, as there was no need to wait for the services to be operational.

An interesting challenge was type validation for storage. We used MongoDB for data storage, which is not a relational database, so we relied on Mongoose for data validation. However, Mongoose schemas are not always very convenient to use. To enable separation between the storage medium and the description of data models, I developed a system that allows simple description of data types within model classes, which are then transformed into Mongoose schemas. An example of a model can be found here.

Finally, some services had specific features. For example, we implemented a caching system to limit calls to the external API and reduce response times. For the user management service, we used JWT (JSON Web Tokens), which allowed us to quickly build a reliable authentication system with persistent user connections.

Result
#

In conclusion, the project was a success. We managed to develop the desired features on time with a good level of reliability. The final application allows users to collect Pokémon cards by opening boosters using data fetched from an external API. It also enables users to chat with Pokémon through our integration of the OpenAI API.

The project’s source code is available on this GitHub repository: