DEV Community

Cover image for Mastering REST API Best Practices with Node.js πŸš€
Biswajit Patra
Biswajit Patra

Posted on

Mastering REST API Best Practices with Node.js πŸš€

Let’s rewrite the same practices using Express.js, the go-to framework for building APIs in Node.js.


1. Foundational Design & Security πŸ›‘οΈ

Start with the basics: secure your API like it’s your grandma’s cookie recipe πŸͺ.

Authentication & Authorization πŸ”’

  • Authentication: Who are you? (Use tokens like JWTs)
  • Authorization: What are you allowed to do? (Role-based access control)

Example: Token Validation

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

const SECRET_KEY = "supersecretkey";

app.get('/protected', (req, res) => {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ error: "Token missing" });
  }
  try {
    jwt.verify(token, SECRET_KEY);
    res.status(200).json({ message: "Access granted" });
  } catch (err) {
    res.status(403).json({ error: "Invalid or expired token" });
  }
});
Enter fullscreen mode Exit fullscreen mode

Token validation like:

  • No token? 🚫 401 Unauthorized
  • Invalid token? πŸš“ 403 Forbidden

Rate Limiter 🚦

Prevent abuse by limiting the number of requests per user.

Example:

  • First 100 requests: 🏎️ Smooth sailing.
  • After 101st request: 🐒 Slow down, buddy.

Use express-rate-limit to limit requests.

Example:

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 1 * 60 * 1000, // 1 minute
  max: 5, // Limit each IP to 5 requests
  message: "Too many requests, please try again later.",
});

app.use('/limited', limiter, (req, res) => {
  res.json({ message: "You are within the limit!" });
});
Enter fullscreen mode Exit fullscreen mode

CORS Validation 🌐

Allow requests from trusted origins only.

Example:

const cors = require('cors');

app.use(cors({
  origin: 'https://trusted-site.com',
}));
Enter fullscreen mode Exit fullscreen mode

Trying from an untrusted site?

Response: "Sorry, not today! πŸ™…"


2. API Structure & Operations πŸ—οΈ

Clear CRUD Endpoints πŸ› οΈ

Examples:

  • GET /users – Get all users πŸ‘₯
  • POST /users – Create a new user ✍️
  • PUT /users/{id} – Update user πŸ› οΈ
  • DELETE /users/{id} – Delete user πŸ—‘οΈ

Confusing endpoints = confused developers = angry developers.

Manage users resource with Express.

Example:

let users = [];

app.use(express.json());

app.get('/users', (req, res) => {
  res.json(users);
});

app.post('/users', (req, res) => {
  const user = req.body;
  users.push(user);
  res.status(201).json(user);
});

app.put('/users/:id', (req, res) => {
  const id = parseInt(req.params.id);
  const user = users.find(u => u.id === id);
  if (user) {
    Object.assign(user, req.body);
    res.json(user);
  } else {
    res.status(404).json({ error: "User not found" });
  }
});

app.delete('/users/:id', (req, res) => {
  users = users.filter(u => u.id !== parseInt(req.params.id));
  res.status(204).send();
});
Enter fullscreen mode Exit fullscreen mode

Status-Based Responses πŸ“œ

Always tell users what’s happening, politely.

Examples:

  • 200 OK – Yay, it worked! πŸŽ‰
  • 201 Created – Your shiny new resource is ready! πŸš€
  • 400 Bad Request – Uh-oh, something’s wrong with your input. 🀷
  • 500 Internal Server Error – Oops, we broke something. πŸ˜“

API Documentation πŸ“š

Use tools like Swagger or Postman.

Why?
Because an undocumented API is like IKEA furniture with no manual. 😭


Consistent Naming Conventions πŸ“

Stick to a pattern and never mix styles.

Example:

  • Good: /api/products
  • Bad: /API/getProducts
  • Ugly: /api/v1/proDuctsGetNow

3. Performance & Scalability πŸš€

Caching Strategy 🧊

Cache responses to save time (and server tears 😒).

Example:

GET /api/cached
Cache-Control: max-age=3600
Enter fullscreen mode Exit fullscreen mode

Use node-cache to cache responses.

Example:

const NodeCache = require('node-cache');
const cache = new NodeCache();

app.get('/cached', (req, res) => {
  const key = 'cachedResponse';
  if (cache.has(key)) {
    return res.json(cache.get(key));
  }
  const data = { message: "This response is cached!" };
  cache.set(key, data, 60); // Cache for 60 seconds
  res.json(data);
});
Enter fullscreen mode Exit fullscreen mode

Blue/Green Deployment πŸŒπŸ’š

Deploy without breaking anything. Test on a β€œblue” version while users stay on β€œgreen.”

Steps:

  1. Deploy the β€œblue” environment.
  2. Test it.
  3. Gradually switch traffic to blue.
  4. Celebrate with cake πŸŽ‚.

Logging Mechanism πŸ“

Log all requests using morgan.

Pro Tip:
Logs should be helpful, not a novel. Nobody likes wading through War and Peace. 🫠

Example:

const morgan = require('morgan');

app.use(morgan('combined'));
Enter fullscreen mode Exit fullscreen mode

4. Quality Assurance πŸ§ͺ

Comprehensive Test Cases βœ…

Test every scenario, even the absurd ones.

Example:

  • Does the API handle invalid inputs?
  • What happens if someone tries to upload a cat picture to /users? 🐱

Error Handling 🚨

Be friendly, even when rejecting users.

Example:

{
  "error": "Invalid email address. Did you mean: abc@gmail.com? πŸ€”"
}
Enter fullscreen mode Exit fullscreen mode

Input Validation πŸ›‚

Validate everything. Trust no one.

Example:

  • User sends "age": "twenty".
  • Response: "Age must be a number."

Conclusion:

A great API isn’t just functional; it’s intuitive, secure, and scalable. Treat your API like your house: keep it clean, secure, and easy to navigate. 🏠✨

And remember: Developers using your API will silently thank you (and maybe buy you coffee β˜•). Or, if you ignore best practices, you might just end up on their β€œwall of shame.” πŸ™ƒ


What’s your favorite REST API best practice? Share below!πŸ‘‡ Let’s chat! πŸŽ‰

Top comments (0)