Skip to content

kakengloh/bagel

Repository files navigation

Bagel.js logo Bagel

Bagel CI status Bagel NPM version

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.

Contents

Features

✅ Routing

✅ Middlewares

✅ JSON parsing

✅ Strongly typed route handlers

Installation

bun add @kakengloh/bagel

Examples

Basic

import { Bagel, Router } from '@kakengloh/bagel';

const app = new Bagel();

app.get('/', async (req, res) => res.send('Hello from Bagel.js!'));

app.listen(3000);

Router

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);

Middleware

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);

Strong typing

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);

Error handling

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);

Benchmark

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

Screenshot 2022-09-09 at 9 19 02 PM

Screenshot 2022-09-09 at 9 15 42 PM

Releases

No releases published

Packages

No packages published