@noturbob/redact
v2.2.1
Published
A simple, user-friendly web API framework built in Node.js.
Maintainers
Readme
🛡️ Redact.js
The Declarative, "Just Return" Framework for Modern Node.js
Why Redact? • Features • Installation • Documentation • Contributing
📖 Introduction
Redact.js is a next-generation micro-framework for Node.js built on a simple premise: Web servers should be simple function calls, not complex state managers.
It abandons the traditional, imperative style of Express (req, res, next) in favor of a clean, declarative syntax. With Redact, you define your API as a structured object, and your logic is pure: You receive input, and you return output. The framework handles the HTTP complexity for you.
🆚 Why Redact? (vs Express)
Most Node.js frameworks are Imperative: you have to tell the server how to send a response step-by-step. Redact is Declarative: you tell the server what the response is.
✨ Key Features
⚡ Declarative Routing
Define your API structure in a readable, nested object syntax.
↩️ "Just Return" Logic
Return an Object/Array for JSON, or a String for text. No res object needed.
🔌 Built-in WebSockets
Real-time support out of the box with app.socket().
🔀 Dynamic Routing
Native support for parameters like /users/:id.
🛡️ Automatic Security
Built-in protection against DoS attacks (1MB body limit).
⚙️ Smart Middleware
Filter requests globally before they hit your logic.
📦 Zero Config • 🚄 Lightning Fast • 🎯 Type-Friendly
💾 Installation
npm install @noturbob/redact wsNote:
wsis required for WebSocket features
🚀 Quick Start
const app = require('@noturbob/redact')();
// Define your API
app.routes({
path: "/",
GET: "Welcome to Redact!", // Returns text
POST: (body) => {
// Returns JSON automatically
return { status: "created", data: body };
}
});
app.listen(3000, () => {
console.log("🚀 Server running at http://localhost:3000");
});📚 Documentation
1️⃣ Declarative Routing
Instead of writing imperative code, describe your API.
app.routes({
path: "/api/v1/status",
GET: { status: "online", uptime: process.uptime() }
});2️⃣ Handling Input (input vs req)
Your route handlers receive two arguments:
input: The parsed data (JSON body for POST/PUT, or empty object).req: The full request context (headers, params, query).
app.routes({
path: "/products",
POST: (body, req) => {
// 'body' is the JSON payload sent by the user
console.log("User Agent:", req.headers['user-agent']);
return { success: true, product: body };
}
});3️⃣ Dynamic Routes
Use : to define dynamic parameters. Access them via req.params.
app.routes({
path: "/users/:id",
GET: (input, req) => {
// GET /users/500 -> { userId: "500" }
return { userId: req.params.id };
}
});4️⃣ Real-Time WebSockets
Redact creates a unified server for both HTTP and WebSockets.
app.socket({
path: '/chat',
open: (ws) => {
console.log("✅ Client connected");
ws.send("Welcome!");
},
message: (ws, data, clients) => {
// 'data' is auto-parsed JSON
// 'clients' is a Set of all connected users (for broadcasting)
clients.forEach(client => client.send(JSON.stringify(data)));
},
close: () => {
console.log("❌ Client disconnected");
}
});5️⃣ Middleware
Middleware runs before every request. It follows the "Just Return" philosophy:
- Return
undefined: Request proceeds to the route handler. - Return a value: Request stops, and that value is sent as the response.
app.use((req) => {
// Log every request
console.log(`[${req.method}] ${req.url}`);
// Security Check
if (req.url.includes("/admin")) {
// Stop the request immediately with a 403-like error
return { error: "Unauthorized Access" };
}
});6️⃣ Query Parameters
Query strings are automatically parsed into req.query.
Request: GET /search?q=javascript&sort=desc
app.routes({
path: "/search",
GET: (input, req) => {
return {
results: [],
meta: {
query: req.query.q, // "javascript"
sort: req.query.sort // "desc"
}
};
}
});🎯 Example: Complete REST API
const app = require('@noturbob/redact')();
let users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
app.routes({
path: "/api/users",
// Get all users
GET: () => users,
// Create new user
POST: (body) => {
const newUser = { id: users.length + 1, ...body };
users.push(newUser);
return newUser;
}
});
app.routes({
path: "/api/users/:id",
// Get specific user
GET: (input, req) => {
const user = users.find(u => u.id === parseInt(req.params.id));
return user || { error: "User not found" };
},
// Update user
PUT: (body, req) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) return { error: "User not found" };
users[index] = { ...users[index], ...body };
return users[index];
},
// Delete user
DELETE: (input, req) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) return { error: "User not found" };
users.splice(index, 1);
return { success: true };
}
});
app.listen(3000);🤝 Contributing
We welcome contributions! Please fork the repository and submit a Pull Request.
- 🍴 Fork the Project
- 🌿 Create your Feature Branch (
git checkout -b feature/AmazingFeature) - 💾 Commit your Changes (
git commit -m 'Add some AmazingFeature') - 🚀 Push to the Branch (
git push origin feature/AmazingFeature) - 🎉 Open a Pull Request
📄 License
Distributed under the MIT License. See LICENSE for more information.
🌟 Show Your Support
If you find Redact.js helpful, please consider giving it a ⭐ on GitHub!
