Express
Your Express routes query the pool directly. If you also want CRUD routes for many entities without writing them, uql-orm/express mounts the HTTP handler as middleware.
Your own routes
Section titled “Your own routes”import express from 'express';import { Post } from './shared/models/index.js';import { pool } from './uql.config.js';
const app = express();
app.get('/posts', async (_req, res) => { const posts = await pool.findMany(Post, { $where: { published: true }, $limit: 20, }); res.json(posts);});
app.listen(3000);The pool shows the uql.config.ts it comes from. Run several writes together in pool.transaction.
Auto-generated CRUD
Section titled “Auto-generated CRUD”Requires Express 5.
import { querierMiddleware } from 'uql-orm/express';import { Post, User } from './shared/models/index.js';
app.use(express.json()); // writes and QUERY read the parsed bodyapp.use('/api', querierMiddleware({ pool, include: [User, Post] }));This serves the wire protocol for each entity, QUERY included. A request for an unknown entity or route falls through with next(), so your own routes can share /api.
Hooks and tenant scoping
Section titled “Hooks and tenant scoping”querierMiddleware takes the handler’s hooks and getContext. Their context is the express.Request:
app.use( '/api', querierMiddleware({ pool, include: [User, Post], getContext: (req) => ({ tenantId: req.user?.tenantId }), async pre({ context }) { if (!context.user) { throw Object.assign(new Error('unauthorized'), { status: 401 }); } }, preSave(ctx) { ctx.body = { ...(ctx.body as object), creatorId: ctx.context.user?.id }; }, }),);req.user is whatever your auth middleware declares on Express.Request (Passport does it for you).
Error handling
Section titled “Error handling”Errors go to next(err), so your error middleware still runs. errorHandler renders the error envelope, honoring a numeric status a hook threw:
import { errorHandler } from 'uql-orm/express';
app.use('/api', querierMiddleware({ pool, include: [User] }));app.use(errorHandler);