Development of a simple shopping cart application
Tags: node, typescript, challenge, assessment
Published: 2021-01-18 21:39:53

# Problem Statement
The challenge today is to build the backend of a simple shopping cart application using [node.js](https://nodejs.org/) and [typescript](https://www.typescriptlang.org/) while using [MySQL](https://www.mysql.com/) as the database and [postman](https://www.postman.com/) for documentation purposes.
This shopping cart is assumed to have categories and products having standard attributes such as (SKU, selling price, stock level, expiration date) etc... and should be able to allow a user add to cart, edit what's in the cart as well as remove from cart.

# Thoughts and structure
The problem is simple enough to tackle on first glance but as I usually say nothing is ever really as it seems. So to up it up a bit, I would set a personal goal of completing the challenge in 3 days or less, I would also be implementing functionality for dynamically manipulating categories and products as well as unit testing all functionalities on this application and developing this article in real-time as I achieve it.
Now with a little extra difficulty, the first thing I'd do is to assign tasks for these 3 days;

* **Day 1:** Folder structure and general functionalities.
* **Day 2:** Unit testing of all functionalities; although this would most like come before each functionality is developed. That way the entire application would be built using TDD ([test-driven-development](https://www.guru99.com/test-driven-development.html))
* **Day 3:** Deployment, documentation and editing of this article.

# Folder Structure
![Folder Structure Image](https://dev-to-uploads.s3.amazonaws.com/i/d6yh8qqzd68e23glk5tt.png)

Although a small and simple application, I structured the application for scale. Below I would discuss the various folders and files and their purpose; were necessary I would include examples.

### Files on the structure
Below I would give short descriptions of key files on the root of the folder and what they are meant for and what role they play. These definitions are by no way standard description of what they are officially but my way of describing what they are and the role they play in my codebase.

1. **.env:** This is the environment variables file; basically all sensitive variables are kept here such as database URLs or keys both secret and public can be kept here.

2. **.env.example:** This file simply provides a structure of how .env should be set up; it could contain just variables without values or consist of mock values and not the actual values

3. **.eslintrc.js:** This holds configurations for eslint which is a linter for javascript and even typescript.
4. **.gitignore:** This consist of files and folders that should be ignored by [git](https://git-scm.com/)(_a version control system_)

5. **generateKeyPair.js:** This holds an algorithm to generate *.pem files i.e public and private key pairs for tokens generation and verification.

6. **nodemon:** This file holds configurations for nodemon which handles spinning up and restarting the development server when specified changes are detected.

7. **package.json:** This file holds information about the application and is generated by npm. It is generated with the `npm init` command

8. **README.md:** This file tells anyone visiting the codebase what to do, how to do it or what the application is about.

9. **tsconfig.json:** This file holds information about how typescript should work on the application and is generated by typescript. It is generated with the `tsc init` command.

### Now, the onto the folders
Below I would describe the folders and the kind of files they are meant to hold; I would not necessarily go in-dept on the files within the folders.

1. **/prisma:** This folder is generated by [prisma](https://www.prisma.io/), which is an [ORM](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) (object-relational mapping) for MySQL which is the database for this shopping cart application. This folder holds the schema and migrations folder which are generated and manipulated by Prisma. Subsequently, the seed.ts file also sits here and its purpose is to populate the database with data to get started. To get started with Prisma and generate the folder, run `npx prisma init`. Given that you have @prisma/cli installed.

> **Note:** This walkthrough assumes you have nodejs installed on your local computer. Go to [Nodejs](https://nodejs.org) if you don't have it.

2. **/src:** This is the working directory of the application and all other paths below would be relative to this.

3. **/api/controllers:** This folder holds controllers that routes link to; these controllers effect validations, perform validations of themselves and call the business logic from service folder.

4. **/api/database/repository:** This folder holds repositories for the business logic and these are simply database connections and actions e.g a repository could have a create method that connects to the database and creates a new record or row with the information passed to it. This is done to enable future change in database. Although this is a small application, Imagine a gigantic application with several hundred endpoints and functionality and all of a sudden there is a need to move from an SQL database to a NoSQL database like MongoDB. It would be cumbersome to go to each page and change database connection. But this way, all the service knows is that it calls a create method and is returned the created record.

5. **/api/routes:** This folder holds all routes/endpoints for the application in question.

6. **/api/validators:** This folder holds request body validation rules using the express validator, other validations like query and params are done within the controller. Although these can also be done with the express validator, I did them within the controller to show different approaches to carrying out validation. Personally, I find using express validator relieving.

7. **/assets:** This folder holds all assets on the application such as images, audios, videos or any type of asset.

8. **/config:** This folder holds configuration files. e.g the `index.ts` file in this folder maps variables from `.env`. Such that access to the .env variables stem from a single source rather than scattered across the application.

9. **/core:** This holds self-defined class-based functionality. For example, this folder holds classes that perform error and response handling among others.

10. **/helpers:** This folder is similar to `/core` although rather than self-defined classes they are simple functions.

11. **/jobs:** This folder holds cron jobs. Basically, pieces of code that have to be run periodically.

12. **/services:** I have made reference to the folder above. This folder holds classes that handle the business logic of the application. Basically, the major functionality of applications is resolved within the classes in the services folder.

13. **/subscribers:** This folder hold events. Events, in this case, are functions that can run in a non-blocking way. Example of this is the sending of a confirmation email once a user registers can be sent to an event within subscribers and it'll run even after a response has been sent to the client.

14. **/types:** This holds all types, interfaces and namespaces to be used throughout the application. Since this is a typescript solution thus the need for types.

# Process Flow
 
![Process Flow Diagram](https://dev-to-uploads.s3.amazonaws.com/i/o7pacslmgz5b4j0vi620.png)

The process flow is fairly straightforward at first glance but I would walk you through the thought process of creating this and possible improvements below.

Once a request is sent to an endpoint on this shopping cart application e.g `http://localhost:3500/auth/v1/register`. It first hits the router for that endpoint and then if it is a public endpoint such as this one it goes to the controller that handles that. If it is a private endpoint like `http://localhost:3500/product/v1/create` it first advances to get you authenticated with a token that should be on the request header and if available and valid it proceeds to the controller for that route. Subsequently, if this is an admin protected route it further checks the authorized user if the type is that of **Admin** and if it is you then proceed to the controller.
All-access routes end up accessing the service class which holds the business logic or actual implementation of the route.

This implementation is sufficient for a simple application such as this but for a more verbose and production-ready application, it is advisable to have a process flow as that below.

![Ideal Process Flow](https://dev-to-uploads.s3.amazonaws.com/i/dli29adarj8a56zjk3cr.png)

Not much has changed from the last one except for the introduction of app keys which give all your route some level of security and preserves your server from any kind of misuse with authorization. App keys are usually issued when you register on the application and opt to use the APIs.

# Unit Testing
- run `npx ts-jest config:init` to initialize tests with typescript 
- run `npx jest --init` to initialize tests with javascript, 

Testing is so important in the development of any application, be it large or small. I use testing to ensure that the core functionalities of each chunk of code are maintained no matter the implementation style or pattern. I also love it because when younger people join the team, it prevents from accidental non-working commits or deployments.

# Let's talk about some why's

#### Why category has status and product doesn't
The way the application is structured is in such a way that you need to link a category to a product; if that is the case if a category were to be deleted what would happen to the link?
So to mitigate this, if you don't want a category you simply switch the status to Inactive. The product doesn't on the other hand because:
1. It stores more data or has more fields
2. It doesn't link to anything or rather no other table is dependent on it.

#### Why static methods over instance methods?
```
//Example of static method in a class
class animal {
  public static color() {
    // ... some functionality here
  }
}

// How you call this method like 
animal.color();
```
Static methods give you direct access to the method without creating an instance of the class; one immediate benefit is it doesn't use memory to store the instance.
Static methods are used where the method has no interaction with class properties. Thus only one of such methods exists per class whereas instance methods you can create as many instances as needed.

```
//Example of instance method in a class
class animal {
  public color() {
    // ... some functionality here
  }
}

// How you call this method like 
const animalInstance = new animal();
animalInstance.color();
```
One of the benefits you see immediately is that with instance methods you can access the constructor function when initializing the class and a draw back as we discussed is the extra pointers in memory to link these instances.

These were the thoughts I had in mind when deciding whether to use static or instance methods.

#### Why use abstract classes?
```
//Example of abstract class
 abstract class animal {
  public color() {
    // ... some functionality here
  }
}
```

An abstract class is more or less a blueprint class i.e you cannot instantiate these classes, rather you extend them and work with them from a subclass. This is because as an abstract class it can have incomplete methods hence the term blueprint class.

#### Why Redis for the cart and not MySQL?
The choice of Redis for the cart system stems from a desire to improve the performance of the cart system. Redis insertion and retrieval big O notation is O(1) whereas that of MySQL is O(n). What this means is that anytime you try to retrieve or insert a record from a Redis server it would take a constant time, while on the MySQL it'll vary based on the number of records stored on the table.

# Conclusion
If there is one thing I believe in it is constant change and evolution and as such, I make it a habit to learn something every time I develop applications. By no way is this a perfect solution to structuring backend applications but I simply collated knowledge from different sources and across time and experience. I am always open to improving on this. Although I initially set out to complete this in 3 days, I ended up completing it in 4 days. This isn't a bad feat; more to come 🚀🚀🚀

Thank you for reading!
You can find the endpoints for this shopping cart application on this postman collection [shopping cart postman](https://documenter.getpostman.com/view/1425723/TVzXBaeT)
The base URL for this shopping cart application is here [base url](https://shop-cartt.herokuapp.com/)
I can be found on Twitter at [https://twitter.com/idiagbordarrel](https://twitter.com/idiagbordarrel) or
please find out more about me on my website at [https://idarrel.netlify.app](https://twitter.com/idiagbordarrel).