Quick Start
This guide walks you through setting up Mongalayer from scratch — defining a schema, configuring access rules, exposing it over HTTP, and querying from a client.
Define a schema
Create a model and Zod schema that describes your MongoDB collection documents:
import z from "zod";
export const projectSchema = z.strictObject({
_id: z.string(),
name: z.string(),
description: z.string().optional(),
owner: z.string(),
members: z.array(z.string()),
createdAt: z.date()
});
export class Project implements z.infer<typeof projectSchema> {
constructor(
public _id: string,
public name: string,
public description: string | undefined,
public owner: string,
public members: string[] = [],
public createdAt: Date = new Date()
) {}
someMethod() {
// Example method on the model
return `${this.name} (${this._id})`;
}
}
import z from "zod";
export const projectSchema = z.strictObject({
_id: z.string(),
name: z.string(),
description: z.string().optional(),
owner: z.string(),
members: z.array(z.string()),
createdAt: z.date()
});
export type Project = z.infer<typeof projectSchema>;
Define access rules
Access definitions control who can read, write, and delete documents. Each role has a filter that determines which documents it applies to, and permissions that control what operations are allowed.
import { AccessPermissions, type AccessConfig } from "@mongalayer/server";
import type { Project } from "../../model/project.js";
export const projectAccess: AccessConfig<Project> = [{
role: "owner",
filter: {
owner: "%%user.id"
},
document: AccessPermissions.ReadWrite,
delete: true
}, {
role: "member",
filter: {
members: { "$in": ["%%user.id"] }
},
document: AccessPermissions.Read
}];
The %% prefix in filter values references properties from the access payload — a user-defined object you pass with each request (typically derived from a JWT or session).
Create the Mongalayer instance
import { MongoClient } from "mongodb";
import { Mongalayer } from "@mongalayer/server";
import { projectSchema } from "../model/project.js";
import { projectAccess } from "./access/project.js";
const mongoClient = new MongoClient("mongodb://localhost:27017");
export const layer = new Mongalayer(mongoClient, {
projects: {
schema: projectSchema,
access: projectAccess
}
}, {
accessDefaults: {
document: AccessPermissions.None // Least permission by default
}
});
Expose over HTTP
Mongalayer does not include its own HTTP server. You integrate it into your existing framework. Here's an example using Lambda or Express:
import { APIGatewayProxyHandlerV2WithJWTAuthorizer } from "aws-lambda";
import { layer } from "./mongalayer.js";
import { ServerError, validateAction } from "@mongalayer/server";
export const handler: APIGatewayProxyHandlerV2WithJWTAuthorizer = async (event, context) => {
try {
// Validate the requested action (database, collection, operation)
const action = validateAction(event.pathParameters!); // Using routed action format
// Access JWT claims as user info
const user = event.requestContext.authorizer.jwt.claims;
const result = await layer.execute(
action, // { database, collection, operation }
event.body!, // The operation payload
{ user } // Access payload — available as %%user in filters
);
return {
statusCode: 200,
body: result
};
} catch (error) {
return {
statusCode: error instanceof ServerError ? 400 : 500,
body: JSON.stringify(error instanceof ServerError ? error.toJSON() : { message: "Internal server error" })
};
}
};
import express from "express";
import { layer } from "./mongalayer.js";
import { ServerError, validateAction } from "@mongalayer/server";
const app = express();
app.use(express.json());
app.post("/api/mongalayer", async (req, res) => {
try {
// Extract and verify your auth token (your responsibility)
const user = await verifyToken(req.headers.authorization);
// Validate the requested action (database, collection, operation)
validateAction(req.body.action); // Using JSON action format
// Execute the action through Mongalayer
const result = await layer.executeRaw(
req.body.action, // { database, collection, operation }
req.body.payload, // The operation payload
{ user } // Access payload — available as %%user in filters
);
res.json(result);
} catch (error) {
if (error instanceof ServerError) {
res.status(400).json(error.toJSON());
} else {
res.status(500).json({ message: "Internal server error" });
}
}
});
app.listen(3000);
Query from a client
Use the Mongalayer client SDK to send typed requests:
import { MongalayerClient } from "@mongalayer/client";
import type { Project } from "../model/project.js";
const client = new MongalayerClient("https://.../api/mongalayer", {
format: "json",
headers: () => ({
"Content-Type": "application/json",
"Authorization": `Bearer ${getToken()}`
})
});
const db = client.db("myapp");
const projects = db.collection<Project>("projects");
// Find all projects the current user has access to
const result = await projects.find({});
console.log(result);
const newProjectId = uuidv4(); // Generate a unique ID for example using uuid
// Insert a new project
await projects.insertOne({
_id: newProjectId,
name: "My Project",
owner: currentUserId,
members: [],
createdAt: new Date(),
updatedAt: null
});
// Update the project
await projects.updateOne(
{ _id: newProjectId },
{ $set: {
description: "Updated description",
members: ["user1", "user2"]
} }
);