rp1 🚀

Blazingly fast and simple web framework for Deno, suitably named after the rocket fuel.

import Router from "https://deno.land/x/rp1/mod.ts";

const router = new Router();

router.get("/", () => "Hello World!");

Deno.serve(router.handle);

Features

Infers parameters from the path, which is matched using URLPattern.

// 'params' is of type { id: string }
router.get("/users/:id", ({ params }) => {
    const id = params.id;
    // ...
});

// 'params' is of type { name: string, ext: string }
router.post("/files/:name(.+).:ext(\\w+)", ({ params }) => {
    const { name, ext } = params;
    // ...
});

Sane error handling. Thrown errors are logged (console.error), returned errors are not. Both get serialized to JSON. Optionally include stack trace.

import { error } from "https://deno.land/x/rp1/mod.ts";

// '{ "status": 418, "message": "I'm a teapot" }'
router.get("/coffee", () => {
    throw error(418, "I'm a teapot");
    // ^ Logged
});

// '{ "status": 402, "message": "Missing $$$", "stack": "..." }'
router.post("/cash", () => {
    return error(402, "Missing $$$").expose();
    // ^ Not logged                    ^ Include stack trace
});

Generates JSON for serializable values returned from handlers.

// '{ "data": [1, 2, 3] }' with a 200 status code
router.get("/json", () => ({ data: [1, 2, 3] }));

You can return Response objects. Note: headers already set on the the context's response object (e.g. by cors middleware) will be appended to the returned Response object's headers.

// 'Hello World!'
router.get("/hello", () => new Response("Hello World!"));

// 'Hello World!' with header
router.get("/hello", ({ response }) => {
    response.headers.set("X-Greeting", "Hello World!");
    // Will be appended to the returned Response object's headers

    return new Response("Hello World!");
});

Easy to use middleware.

// Simple request logger
router.use(async ({ request }, next) => {
    const method = request.method;
    const url = new URL(request.url);
    const path = url.pathname;

    console.log(`${method} ${path}`);

    await next();
});

CORS middleware included.

import cors from "https://deno.land/x/rp1/middleware/cors.ts";

router.use(cors());

...which is easily configurable.

import cors, { echo } from "https://deno.land/x/rp1/middleware/cors.ts";

router.use(cors({
    // Skip CORS for public paths
    skip: ({ request }) => {
        const url = new URL(request.url);
        return url.pathname.startsWith("/public/");
    },
    origin: echo,
    methods: ["GET", "POST"],
    headers: "Content-Type",
    // ...
}));

Supports sub-routes.

router.sub("/stats")
    .get("/users", () => users.length) // GET /stats/users
    .get("/posts", () => posts.length); // GET /stats/posts

Uses Deno's native Request object, so WebSockets are supported out of the box.

router.get("/ws", ({ request }) => {
    const { socket, response } = Deno.upgradeWebSocket(request);

    socket.onopen = () => {
        console.log("Socket opened!");
    };

    // ...

    return response;
});