Production Ready REST APIs in a Monolithic Architecture
Before APIs
Before we deep dive into APIs, we have to take a look at some common things,
- HTTP Methods: APIs use HTTP methods to define what kind of action to take on a resource.
- Endpoint: It is a URL which represents a specific resource on the backend.
- Headers: They contain the metadeta about request and response like auth tokens, sessions, etc.
- Request Body: Info which is passed from the frontend to the backend in form of
jsondata. - Response Body: Info which passes from the backend to the frontend in form of
jsondata.
Status Codes:
Here are some common status codes.
- 200
OK-> The request was successful. - 201
Created-> A new resource was created. - 204
No Content-> Request succeeded but no body returned - 400
Bad Request-> The client sent invalid data - 401
Unauthorized-> Missing authentication - 403
Forbidden-> Authenticated but not allowed. - 404
Not Found-> The resource doesn't exist. - 500
Internal Server Error-> Something went wrong in the server.
REST APIs - The basics
REST stands for Representational State Transfer and is an architectural style for APIs. It follows a structured approach where client and server communicate through URLs and Standard HTTP Methods like GET, POST, PUT, DELETE. They are Stateless, which means that each request is independent and doesn't rely on previous ones. They typically use json.
REST APIs often use HTTP methods like GET, POST, PUT, PATCH and DELETE and are useful for making CRUD (Create, Read, Update, Delete) Applications. It is based on the Client-Server model where client and server operate independently, allowing scalability. Responses from the server can be cacheable or non cacheable to improve performance. REST APIs can be deployed in multiple layers which helps with security and scalability, they also follow a set of conventions and constraints such as consistent URL paths and standardized HTTP methods which ensures smooth communication between the client and the server.
There are 6 Guiding Principles of REST APIs:
- Uniform Interface - A consistent and uniform interface for interactions between client and server using standard HTTP methods.
- Client-Server - The client and the server are separate entities that communicate over a network, improving scalability and flexibility.
- Stateless - Each request from the client to the server must contain all the information needed to understand and process said request, the server cannot reference previously stored context information. Thus, the client application must entirely keep the session state.
- Cacheable - A response should label itself as cacheable or non cacheable. If the response is cacheable, the client can reuse the data for later requests, improving performance.
- Layered System - The architecture can be composed of heirarchial layers based on component behaviour. Each component cannot see beyond the immediate layer they interact with. Example - MVC (Model, View, Controller) where Models handle data and business logic, Views handles user interface and Controllers act as a bridge between the two.
- Code on Demand (optional) - Client functionality can be extended by donwloading and executing code in the form of applets or scripts. The downloaded code reduces features required to be pre implemented and servers can provide the part of features in the form of code.
REST API in a Monolithic Architecture
In a monolithic backend architecture, all components are combined into a single, unified codebase. This architectural pattern creates a system where all functions share the same resources and communicate internally without network boundaries.
A pure monolithic architecture runs a single process, points to one database and ships one deployable unit.
Early apps used the monolithic architecture because of its simplicity, practicality and constraints of tecnology. Monolithic architectures are still a very strong choice for:
- • Early Stage Startups
- • Small to Medium Scale Applications
- • MVPs that want rapid iteration and simplicity
Configuration
The Monolithic REST API often follows a specific configuration which we are going to see now.
src/
|- config/
|- middleware/
|- models/
|- controllers/
|- routes/
|- utils/
|- services/
|- app.js
Now lets look at various things in detail,
- The
config/folder usually contains the application config, environment variables and the database setup. You can also setup database in adatabase/folder but it is optional. - The
middleware/folder contains middlewares, middlewares as the name suggests, run between request arrival and response being sent and usually are used to check authorization, rate limiting, etc. - The
models/folder contains your database schemas / ORM models. - The
controllers/folder is used to handle the(req, res) => {}part, the requests and response behind the api. - The
routes/folder is used to define endpoints and group routes together. - The
services/folder is used to handle heavy work. The main difference between thecontrollerand theserviceis that the controllers only manage incoming requests and have the flow of data, while services handle business logic and data processing. - The
utils/folder (alternativelyhelpers/) contains reusable code like formatters and token helpers.
Some optional additions:
validators/validation functions which check if requests are validerrors/for custom error classes and handlingtests/for testing
Best Practices - Versioning
To manage complexity, we have to start with versioning our APIs. Versioning helps us to iterate faster when changes are found in the API.
APIs only need to be verisioned when there are breaking changes - changing format of response data, changing the request or response data type, removing a part of the API.
The most common way to version APIs is URI verisioning.
http://api.example.com/v1/users
http://api.example.com/v2.1/users
This versioning strategy is easy to implement and very flexible. However, it can lead to cluttered URLs and managing multiple versions can be challenging.