Skip to main content

Introduction

Welcome to Lesan โ€” a blazing-fast, cross-platform web framework and ODM for building modern APIs with MongoDB.

What is Lesan?โ€‹

Lesan is a new way to build web servers and NoSQL data models. It combines the flexibility of GraphQL with the performance of direct MongoDB queries, all while maintaining complete end-to-end type safety.

Key Featuresโ€‹

  • Client-Driven Projections โ€” Fetch exactly the data you need, nothing more
  • Automatic Bi-Directional Relations โ€” Define once, get both sides for free
  • End-to-End TypeScript Safety โ€” Types generated from your actual code
  • Cross-Platform โ€” Runs on Node.js, Bun, and Deno
  • Extreme Performance โ€” Much faster than traditional ORMs or GraphQL
  • MongoDB Native โ€” Full compatibility with MongoDB's powerful query language

Quick Startโ€‹

Installationโ€‹

# Node.js
npm install @hemedani/lesan mongodb superstruct

# Bun
bun add @hemedani/lesan mongodb superstruct

# Deno
import { lesan } from "jsr:@hemedani/lesan";

Create Your First APIโ€‹

import { lesan, MongoClient, string, number, object, ObjectId } from "@hemedani/lesan";

// 1. Initialize
const coreApp = lesan();

// 2. Connect to MongoDB
const client = await new MongoClient("mongodb://localhost:27017/").connect();
coreApp.odm.setDb(client.db("myapp"));

// 3. Define a model
const countries = coreApp.odm.newModel("country", {
name: string(),
population: number(),
}, {});

// 4. Define an action
const addCountry = async (body) => {
return await countries.insertOne({
doc: body.details.set,
projection: body.details.get,
});
};

coreApp.acts.setAct({
schema: "country",
actName: "addCountry",
validator: object({
set: object({ name: string(), population: number() }),
get: object(),
}),
fn: addCountry,
});

// 5. Start the server
await coreApp.runServer({
port: 8000,
playground: true,
typeGeneration: true,
});

Test Your APIโ€‹

curl -X POST http://localhost:8000/lesan \
-H "Content-Type: application/json" \
-d '{
"model": "country",
"act": "addCountry",
"details": {
"set": { "name": "Iran", "population": 85000000 },
"get": { "name": 1, "population": 1 }
}
}'

Or open http://localhost:8000/playground to use the interactive API explorer.

Documentation Structureโ€‹

SectionDescription
API ReferenceComplete API documentation
Server APIServer setup, actions, context
Models & ODMSchemas, relations, CRUD operations
Queries & ProjectionsClient-driven projections and aggregation
Type SystemTypeScript types and generated code
Cross-PlatformNode.js, Bun, and Deno support

Why Lesan?โ€‹

vs Traditional RESTโ€‹

FeatureRESTLesan
Over-fetchingCommonEliminated
Under-fetchingCommonEliminated
Endpoint countManyOne
Type safetyManualAutomatic
RelationsManual joinsAutomatic

vs GraphQLโ€‹

FeatureGraphQLLesan
FlexibilityHighHigh
PerformanceResolver overheadDirect MongoDB
ComplexityHighLow
Type safetySchema-firstCode-first
MongoDBNeeds wrapperNative

vs Traditional ORMsโ€‹

FeatureORMsLesan
RelationsForeign keysEmbedded (denormalized)
QueriesAbstractedNative MongoDB
ProjectionsLimitedClient-driven
PerformanceGoodExcellent

Built with Lesanโ€‹

Lesan is already powering real production applications. Here's a showcase of what can be built with it.

ZiWound โ€” War Crimes Documentation Platformโ€‹

ziwound.com is a full-stack war crimes documentation system built entirely with Lesan. It's a serious, production-grade application that demonstrates Lesan's capabilities at scale. ZiWound is open source โ€” you can read the entire codebase on github.com/hemedani/ziwound and study the real models, acts, and utilities end-to-end.

Backend (Deno + Lesan + MongoDB):

  • 15 data models โ€” user, report, document, file, country, province, city, category, tag, blogPost, warCriminal, confirmation, and more
  • 98 actions (acts) โ€” the entire API is expressed as acts, with per-act validators handling input (set) and client-driven projections (get)
  • Rich relation graph โ€” reports link to reporters, documents, tags, categories, hostile countries, and locations, with Lesan automatically embedding and syncing the reverse relations (e.g. each user keeps a sorted, limited list of their reports)
  • GeoJSON support โ€” native MongoDB geospatial queries for interactive map-based exploration (MapLibre GL + Leaflet)
  • JWT auth & RBAC โ€” role-based access control (Ghost, Manager, Editor, Ordinary) built on the request context + preValidation/preAct hooks
  • Production deployment โ€” Dockerized, with CORS config, static file serving, rate limiting, and generated TypeScript declarations (typeGeneration: true)

Frontend (Next.js):

  • Nine languages with full RTL/LTR layout flipping (Persian, English, Arabic, Chinese, Portuguese, Spanish, Dutch, Turkish, Russian)
  • Secure multi-language report submission with file attachments, location, and metadata
  • Advanced search and filtering of documented incidents, a blog section, and a comprehensive admin panel
  • PWA support and server actions for type-safe backend communication

The whole stack โ€” data modeling, relations, validation, and the client-server contract โ€” is driven by Lesan's generated types, proving that Lesan scales from a quick prototype to a multi-language production platform.

Next Stepsโ€‹

Communityโ€‹