meebo
v0.3.0
Published
the missing api contract validation for express js
Readme
The missing API validation library for Express
Installation • Usage • OpenAPI
Why Meebo?
Express is the most popular Node.js framework, but it was built before TypeScript existed...
Existing solutions require too much:
- tRPC: Amazing, but requires you to abandon REST...
- ts-rest: Powerful, but requires defining contracts separately...
- tsoa: Generates code from decorators, heavy setup...
Meebo takes a different approach: Keep your Express routes exactly as they are and simply add your schema
The Problem
const router = express.Router();
router.post("/users", (req, res) => {
const user = req.body; // req.body is type any and not validated at runtime
res.json({ user }); // res.json returns anything and is not validated either
});The Solution
import { TypedRouter, swagger } from "meebo";
import { z } from "zod";
const router = TypedRouter(express.Router());
const UserSchema = z.object({
name: z.string(),
email: z.string().email(),
});
router.post("/users", { request: UserSchema, response: UserSchema }, (req, res) => {
req.body; // typed + validated using UserSchema ✅
res.json({ name: "John", email: "[email protected]" }); // typed + validated using UserSchema ✅
});You now have an API where
- TypeScript knows the exact shape of
req.body,req.query,req.params, and your response - Full autocomplete and intellisense on your requests, responses, queries, params, and headers
- Zod validates everything at runtime, ensuring data matches and gives very helpful errors
- Swagger UI and OpenAPI json generated from all your endpoints and schema
Install
npm install meebo zod express
npm install -D typescript @types/express @types/nodeRequirements: TypeScript, Express 5+, Zod 3 or 4
Usage
// Validate request body, response, query, params, headers
router.get(
"/users/:id",
{
params: z.object({ id: z.string() }),
query: z.object({ limit: z.coerce.number().optional() }),
response: UserSchema,
},
(req, res) => {
req.params.id; // string
req.query.limit; // number | undefined
},
);OpenAPI / Swagger
Add swagger() as the last middleware to serve swagger ui docs at /docs:
const app = express();
app.use("/api", router);
app.use(swagger("My API"));Schema Metadata
Use .openapi() on any Zod schema to add descriptions, examples, and more (powered by zod-to-openapi):
const UserSchema = z
.object({
name: z.string().openapi({ example: "John" }),
email: z.string().email().openapi({ example: "[email protected]" }),
})
.openapi({
description: "A user object",
example: { name: "John", email: "[email protected]" },
});https://github.com/user-attachments/assets/d47bf5c3-a2b5-4ee8-885d-8c9d1db9fcd8
License
ISC
