Skip to content

A lightweight, beginner-friendly Node.js web framework for building clean REST APIs β€” with built-in routing, middleware, and JSON parsing. Now with CI/CD powered by GitHub Actions πŸš€

Notifications You must be signed in to change notification settings

noturbob/Redact

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ›‘οΈ Redact.js

The Declarative, "Just Return" Framework for Modern Node.js

npm version License: MIT 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.

Feature 🐒 Express.js (The Old Way) πŸš€ Redact.js (The New Way)
Routing Scattered app.get, app.post calls. Hard to visualize structure. Single Object Tree. See your entire API hierarchy at a glance.
Response Manual res.status(200).json({...}). Just return {...}. The framework automates status & headers.
Async Logic Easy to forget .catch(next). Crashes server on unhandled errors. Native Async/Await. Thrown errors are automatically caught and handled safely.
Real-Time Requires external libraries (socket.io) and complex setup. Built-in WebSockets. Handles HTTP and WS on the same port effortlessly.
Boilerplate High. Middleware for everything (body-parser, cors, etc). Zero. Automatic JSON parsing, query parsing, and security limits included.

✨ 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 ws

Note: ws is 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.

  1. 🍴 Fork the Project
  2. 🌿 Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. πŸ’Ύ Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. πŸš€ Push to the Branch (git push origin feature/AmazingFeature)
  5. πŸŽ‰ 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!


Built with ❀️ by noturbob

⬆ back to top

About

A lightweight, beginner-friendly Node.js web framework for building clean REST APIs β€” with built-in routing, middleware, and JSON parsing. Now with CI/CD powered by GitHub Actions πŸš€

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages