/phone_corp

Phone Company Module - Node / Express / TypeScript / Jest ๐Ÿ“ž Dashboard designed for stock management in a phone company. Both routes and functions have been successfully tested. Readme available.

Primary LanguageTypeScript

Phone Corp Module

๐Ÿ’ฌ   About

This is an exercise from a company interview process for Junior full-stack developers apply.
The goal of this exercise is to create a backend module for a phone company
to list products and create orders from them.

โš™๏ธ   Tech Stack

NodeJS  Express.js  TypeScript  MongoDB

๐Ÿ”ฉ   Main features

  • Retrieve the list of products present in the database.
  • Retrieve a specific product.
  • Place an order of products.
  • Display the list of orders.
  • Handle non-passing cases: what to do if the requested product does not exist ? What if the order contains products not present in the database ?
  • Qualitatives tests and documentation should be written.

๏ผŸHow to run it

  1. npm install to install depencies.
  2. npm start to run the PhoneCorp system. The server will listen port :4000.
  3. npm run test to run tests.
  4. You can create a .env file and place MONGODB_URL= followed by your connection string provided by MongoDB to interact with your database.

๐Ÿ“ Architecture

  • I decided to create this project trying to build some layers to be able to have a clean and maintenable code.
  • I found services --> utils --> controllers --> routes a good path to design the project pattern.
  • Created a config folder to store mongoose connection module exports and env with PORT config.
  • Decided to create my services and utils folders into database because it interacts directly with it.
  • Defined my tests in two differents folders functions and routes, both contains order and product.

๐Ÿš Routes

Routes Methods Function
/product/create POST Create a product
/product/stock GET List all existing products sorted by brand
/product/:id GET Retrieve a product with :id
/product/ GET Handle error if :id not provided
/order/create POST Pass an order
/order/history GET List all orders sorted by date

๏ผŸ How to use

  • For /product/stock, product/ and order/history routes, you just have to send a GET request.

  • /product/create :

//example body to send to create a product

{
    "brand": "iPhone", // string
    "model": "15 Pro Max", // string
    "sku": 123456, // number
    "price": 1599, // number
    "quantity": 3 // number
}
  • /product/:id :

http://localhost:4008/product/ folloed by existing database ID
  • /order/create :

//example body to send to create an order

// replace examples Id by existing database ID, anyway if you provide a wrong ID the response will alert you.

{
    "order": [
        {
            "productId": "64bed8f2687ae0df0d3675fd",
            "quantity": 2
        },
           {
            "productId": "64bed8f2687ae0df0d3675fd", "quantity": 2
        },
           {
            "productId": "64bf01c275bc8f6ff962ae34", "quantity": 2
        }
    ]
}

๐Ÿงฑ Process

  • Sent all my request with Postman when working on the project and set up all my environment to be comfortable.

jest

โŒ Errors handling

  • When I created my routes i decided to handle some errors handlers :
-product/create => 400(at least 1 product information not provided / quantity ordered is < 1)
                   409(SKU already exists)
                   500(errors)

product/stock   => 500(errors)

product/:id     => 404(ID not found in DB)
                   500(error)

product/        => 400(product/:id not provided)

order/create    => 400(0 product placed on order / negative product quantity ordered)
                   500(errors)
                   alert(Object.JSON response: ID doesnt exists and cannot be placed in order)

order/history   => 500(errors)

๐Ÿงช Tests

  • I decided to use Jest, SuperTest and mongodb-memory-server to deal with testing.
  • This setup is pretty efficient and not that hard to use.
  • I defined 33 tests which covers all the functions / API calls and DB interactions that i found relevant to test.
  • As explained you can run all tests by running npm run test or you can do this separately with the commands i created in package.json :
 npm run test:getOrder
 npm run test:createOrder
 npm run test:createProduct
 npm run test:getProductStock
 npm run test:getProductById
 npm run test:productFunc
 npm run test:orderFunc

๐Ÿ’ช๐Ÿผ Possible improvements

  • Create independents functions to handle errors in API calls.
  • Upgrading the module with product/delete and product/update/:id paths.
  • Create an assets folder containing a json file to store all the reusable string messages.
  • Edit the project config to be able to import with @/whatever instead of ../../../whatever.
  • Move all the functions contained in getOrder.ts to keep code cleaner and more maintenable.
  • Refactoring some parts of my code to be clearer and more modular.
  • Use a Schema Validator like Zod to avoid some possibles issues if the app growth.
  • Add an Auth, Login, Register and Roles.
  • Add a customer ID to track who passed orders.
  • Frontend interface.

๐Ÿ™‡๐Ÿป What did i learn, improve and discover

  • I Improved my TypeScript's knowledges.
  • I improved my vision of project architecture.
  • I learned how to run tests properly and to test what seemed relevant to me.
  • I learned how to write and structure a well documented README file.
  • I discovered mongodb-memory-server which is pretty good for testing interaction with database.

๐Ÿ’ฅ Annoying encountered issues and how i solved them

jest Jest / TypeScript compatibility

  • Had troubles with Jest and TypeScript compatibility, my tests crashed everytime.

  • After some investigations i discovered that i needed to install :

    babel/core
    babel/preset-env
    babel/preset-typescript

  • Create a babel.config.js file and put this inside :
module.exports = {
  presets: [
    ["@babel/preset-env", { targets: { node: "current" } }],
    "@babel/preset-typescript",
  ],
};
  • Also create a jest.config.ts and put this inside :
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  testEnvironment: "node",
  preset: "ts-jest --config=jest.config.ts",
  transformIgnorePatterns: ["/node_modules/(?!(uuid)/)"],
};

๐Ÿ”Š Address already in use when testing

  • Had troubles running npm run test because tests failed with this error message :
listen EADDRINUSE: address already in use :::4008
  • After some investigations i discovered that i needed to mention (require.main === module) && condition in my index.ts :
require.main === module &&
  server.listen(config.port, () => {
    console.log(
      `โšก๏ธ[server]: Server started ๐Ÿš€ running at http://localhost:${config.port}`
    );
  });
  • With this condition the server won't force listening on port 4008 between each tests.

๐Ÿ›’ create/order issues

  • Encountered some issues with order/create API Response when an order was passed.
  • I created a new branch, reworked my schemas and made it works properly.
  • Merged it when properly fixed.
  • Also had trouble trying to export functions outside of getOrder.ts, had a lot of TypeScript errors
    and bugs and i lost too much time trying to clean this.
  • It works well like that but it's kind of dirty part of my code, i should rework this later on !

๐Ÿ”ญ Conclusion

  • Working on this project was really exciting !
  • I tried my best but can do way better if i restart from scratch a second time.
  • But I had to make choices because i lost a lot of times trying to refactor and deal with errors.
  • I started by establishing a little sketch on Excalidraw and took some notes to define the logic, structure and path i wanted to create.
  • I improved my skills working on this project and i consider this as a really good point for me.
  • A little bit frustrated to had no time to create a little frontend interface to have something to show.