View on GitHub

Building RESTful APIs with Nodejs

Building fast, scalable and secure RESTful services with Node, Express and MongoDB

RESTful APIs with NodeJS, Mongodb and Express

Building RESTful API REST services with Node.js, Express.js and Mongoose.js

Scenario

A brokerage firm needs to have an API service to process a set of buy/sell orders. This API must have two endpoints, the first one to create an account with the initial balance, and the second one to send the buy/sell orders. For each order, the API expect to receive a timestamp (for when it took place), an operation type (buy or sell), issuer name (stock’s identifier), a total amount of shares (a positive integer number), and the unitary price of the share (a positive real number).

Please make sure that all the following business rules are validated:

  1. Insufficient Balance: When buying stocks, you must have enough cash in order to fulfill it.
  2. Insufficient Stocks: When selling stocks, you must have enough stocks in order to fulfill it.
  3. Duplicated Operation: No operations for the same stock at the same amount must happen within a 5 minutes interval, as they are considered duplicates.
  4. Closed Market: All operations must happen between 6am and 3pm.
  5. Invalid Operation: Any other invalidity must be prevented.

A business rule violation is not consired an error, since in the real world they may happen. In case any happens, you must list them in the output as an array, and have no changes applied for that order, following to process the next order.

Required API endpoints.

Create investment account

The first endpoint will be used to create an investment account. The expected contract is:

Request:

POST /accounts

Body:

  {
   "cash": 1000
  }

Expected response:

  {
    "id": 1,
    "cash": 1000,
    "issuers": []
  }

Send a buy/sell order

The second endpoint will be used to send orders into a specific account.

Request:

POST /accounts/:id/orders

Body:

{
"timestamp": 1571325625,
"operation": "BUY",
"issuer_name": "AAPL",
"total_shares": 2,
"share_price": 50
}

Expected response:

{
      "current_balance": {
      "cash": 900,
      "issuers": [
          {
          "issuer_name": "AAPL",
          "total_shares": 2,
          "share_price": 50
          }
      ]
    },
    "business_errors": []
}

Multiple issuers are accepted, so given this other payload:

 {
  "timestamp": 1583362645,
  "operation": "BUY",
  "issuer_name": "NFTX",
  "total_shares": 10,
  "share_price": 80
  }

Expected respose:

{
  "current_balance": {
    "cash": 0,
    "issuers": [
        {
          "issuer_name": "AAPL",
          "total_shares": 2,
          "share_price": 50
        },
        {
          "issuer_name": "NFTX",
          "total_shares": 10,
          "share_price": 80
        }
    ]
  },
  "business_errors": []
}

If a business error occurs, the expected response should be:

{
"current_balance": {
  "cash": 1000,
  "issuers": []
  },
  "business_errors": ["CLOSE_MARKET"]
}

Translating business rules and requirements into code

Choosed technologies and tools

How to use the code

alt text

Testing the API with Postman

Creating a new account alt text

Buy shares alt text alt text

Sell shares alt text

Insufficient Stocks alt text

Checking collections and documents in MongoDB Compass

alt text

Conclusions

Extensible The application code was designed to be extensible, if you want to add new APIs, just add the file of the new api inside the “routes” folder and there is no need to modify the existing code, then add the new controllers in the “controllers” , if we want add a new data model only use the “models” folder with the new mongoose schema, this code architecture allows me to reuse existing code from a controller or a model, it also allows me to add filters to the original request and validate the payload using middlewares.

Scalable The existing code is non-blocking code, because of this, it can be easily scaled, if there is an APIs that are more in demand than others, it could be separated in another server or container, this allows copying the code quickly because each api is related to a set of separate modules allowing high granularity. The application has a middleware called “authenticated” that manages a JWT, this allows the application to be stateless and facilitates horizontal scaling, since the API consumption can be used by millions of users, and the server does not need to save the session user.

Testable

The application has a file called tests.js in the “test” folder, it already has unit tests, it must be taken into account that unit tests depend on the situation, so if you want to run them again you have to create new cases. Here I show an image of the execution of the unit tests and the report of the coverage of those tests.

Unittests result

alt text

Coverage result

alt text

Contributing and Feedback

Any ideas or feedback about this repository?. Help me to improve it.

Authors

License

This project is licensed under the terms of the MIT license.