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" });
}
});
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!" });
});
CORS Validation π
Allow requests from trusted origins only.
Example:
const cors = require('cors');
app.use(cors({
origin: 'https://trusted-site.com',
}));
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();
});
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
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);
});
Blue/Green Deployment ππ
Deploy without breaking anything. Test on a βblueβ version while users stay on βgreen.β
Steps:
- Deploy the βblueβ environment.
- Test it.
- Gradually switch traffic to blue.
- 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'));
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? π€"
}
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)