Database Proxy with Access Control

1.0.0 · active · verified Wed Apr 22

database-proxy is a core component within the Laf serverless ecosystem, designed to function as a 'super API' that allows client applications to securely and directly interact with databases (like MongoDB, with future support for MySQL as indicated by keywords) via HTTP. It enables frontend developers to perform database operations without needing a dedicated backend API layer for common CRUD actions. The security and access patterns are enforced through a set of configurable Access Control List (ACL) rules. Currently, the package is in active beta development, with version `1.0.0-beta.14` being the most recent significant release. Releases are frequent, indicating rapid development and feature iteration. Its key differentiator is simplifying backend development by shifting database access control to the proxy layer, significantly reducing the boilerplate traditionally associated with data APIs in BaaS and serverless architectures.

Common errors

Warnings

Install

Imports

Quickstart

Sets up an Express.js server to expose a secure HTTP endpoint for MongoDB operations using `database-proxy`. It demonstrates how to configure access control rules with `Policy`, inject user context (like `uid` and `admin` status), and handle incoming client database requests, ensuring all operations comply with predefined security policies. This example assumes a MongoDB instance is running locally or accessible via `MONGO_URI`.

const express = require('express');
const { Proxy, MongoAccessor, Policy } = require('database-proxy');
const { MongoClient } = require('mongodb');

const app = express();
app.use(express.json());

// Dummy function for token parsing (replace with actual implementation)
function parseToken(authorizationHeader) {
  // In a real application, this would validate a JWT and extract user info
  if (authorizationHeader && authorizationHeader.startsWith('Bearer ')) {
    const token = authorizationHeader.substring(7);
    // For demonstration, let's assume a valid token means uid is 'testuser'
    // In production, decode and verify the token properly.
    return { uid: 'testuser', admin: true }; // Example: always admin for demo
  }
  return { uid: null, admin: false };
}

// Design the access control policy rules
const rules = {
  categories: {
    "read": true,
    "update": "$admin === true", // Only admin can update
    "add": "$admin === true",    // Only admin can add
    "remove": "$admin === true"
  },
  articles: {
    "read": true,
    "update": "$userid && $userid === query.createdBy",
    "add": "$userid && data.createdBy === $userid",
    "remove": "$userid === query.createdBy || $admin === true"
  }
};

const mongoUri = process.env.MONGO_URI ?? 'mongodb://localhost:27017';
const client = new MongoClient(mongoUri);

async function setupDatabaseProxy() {
  try {
    await client.connect();
    console.log('Connected to MongoDB');

    const accessor = new MongoAccessor(client);
    const policy = new Policy(accessor);
    policy.load(rules);

    const proxy = new Proxy(accessor, policy);

    app.post('/proxy', async (req, res) => {
      const { uid, admin } = parseToken(req.headers['authorization']);

      const injections = {
        uid: uid,
        admin: admin
      };

      const params = proxy.parseParams(req.body);

      const result = await proxy.validate(params, injections);
      if (result.errors) {
        return res.status(403).send({
          code: 1,
          error: result.errors
        });
      }

      const data = await proxy.execute(params);
      return res.send({
        code: 0,
        data
      });
    });

    const port = 8080;
    app.listen(port, () => console.log(`Database Proxy listening on http://localhost:${port}/proxy`));

  } catch (error) {
    console.error('Failed to connect to MongoDB or start server:', error);
    process.exit(1);
  }
}

setupDatabaseProxy();

view raw JSON →