Bagel is a tiny and expressive web framework for Bun.js for building web APIs.
Inspired by Express.js and Koa.js.
Here we treat Typescript as first class citizen, hence every request handler supports generic and you may specify your own typing of request params, query, body and response body.
✅ Routing
✅ Middlewares
✅ JSON parsing
✅ Strongly typed route handlers
bun add @kakengloh/bagel
import { Bagel, Router } from '@kakengloh/bagel';
const app = new Bagel();
app.get('/', async (req, res) => res.send('Hello from Bagel.js!'));
app.listen(3000);
import { Bagel, Router } from '@kakengloh/bagel';
// Create items router
const items = new Router();
items.get('/', async (req, res) => res.json({ items: [] }));
// Create v1 router
const v1 = new Router();
// Mount items router to v1 router
v1.mount('/items', items);
const app = new Bagel();
// Mount v1 router to app
app.mount('/v1', v1);
app.listen(3000);
import { Bagel, Router } from '@kakengloh/bagel';
const app = new Bagel();
// Before middleware
app.use(async (req, res, next) => {
console.log('Before');
});
// Route handler
app.get('/', async (req, res) => res.send('Hello from Bagel.js!'));
// After middleware
app.use(async (req, res, next) => {
console.log('After');
});
app.listen(3000);
import { Bagel, Handler } from '@kakengloh/bagel';
// Entity
interface Bread {
bakeryId: string;
name: string;
price: number;
}
// Path parameters
interface PathParams {
bakeryId: string;
}
// Query parameters
type QueryParams = Record<string, unknown>;
// Request body
type RequestBody = Bread;
// Response body
interface ResponseBody {
bread: Bread;
}
// Route handler with all types specified
const createBread: Handler<
PathParams,
QueryParams,
RequestBody,
ResponseBody
> = async (req, res) => {
const { name, price } = req.body; // Typed inferred
const { bakeryId } = req.params; // Typed inferred
const bread: Bread = {
bakeryId,
name,
price,
};
return res.json({ bread }); // Typed checked
};
const app = new Bagel();
app.post('/bakeries/:bakeryId/breads', createBread);
app.listen(3000);
import { Bagel } from '@kakengloh/bagel';
const app = new Bagel({
// Every error thrown will go through this function
// Here you can return a custom response
error: async (res, err) => {
return res.status(400).json({ error: 'Bad request' });
},
});
app.get('/error', async () => {
throw new Error('Some error');
});
app.listen(3000);
Below is a simple benchmark of Bagel.js and Express.js conducted on my machine using autocannon (12 threads, 500 concurrent connections, 10 seconds)
The output shows that Bagel.js can handle ~2.67x more requests than Express.js