Hooks for the backend.
- DX improvements
- state management
- logger
- unified error handling interface
uze
allows you to access the context of a request with zero hassel in backend environments and provides helpers for
logging, error handling & managing state
// route handler for getting user info
export default async function getUserInfo() {
const { request } = uzeContext();
const db = await uzeDatabase();
const user = await db.execute("...");
return Response.json({
user,
})
}
npm install uze
- make sure you enable node compatibility in your
wrangler.toml
file
import {createUze} from "uzeful";
import type {D1Database, Request} from "@cloudflare/workers-types";
export interface Env {
DB: D1Database;
}
const uze = createUze<Env, Request>();
// hook to use in all of your route handlers
export const uzeContext = uze.hooks.uzeContext;
// code that processes requests
const handler = async (): Promise<Response> => {
const context = uzeContext();
...
}
export default {
fetch: async (req: Request, env: Env, ctx: any) => {
return await uze.handle(
{
request: req,
env,
waitUntil: ctx.waitUntil,
rawContext: ctx,
},
handler
);
},
};
import {createRouter} from "uzeful/router";
const router = createRouter()
.all("*", () => {
return Response.json({message: "Hello World"});
});
export default {
fetch: async (req: Request, env: Env, ctx: any) => {
return await uze.handle(
{
request: req,
env,
waitUntil: ctx.waitUntil,
rawContext: ctx,
},
router.handler,
);
},
};
Making a hook is as simple as making a function with the prefix uze
. No magic required. As long as you run these
functions within the handler
function you pass to uze
you will be able to access the current request context.
export const uzeDatabase = async () => {
const { env } = uzeContext();
return env.DB;
}
You can use the uzeAfter
hook to run code after the response has been created. This can be useful when you want to add
headers to a response, such as CORS.
import {uzeAfter} from "uzeful";
import {createRouter} from "uzeful/router";
const router = createRouter()
.all("*", async () => {
uzeAfter((response) => {
response.headers.set("Access-Control-Allow-Origin", "*");
});
})
.get("/users/:id", userHandler);
A lot of the time you want to manage state related to a single request. uze
provides a way to do this with useState
.
import {uzeState, createStateKey} from "uzeful";
export interface UserAccount {
id: string;
name: string;
}
const USER_ACCOUNT_KEY = createStateKey<UserAccount>("user-account");
export default async function getUserInfo() {
const [getUserAccount, setUserAccount] = uzeState(USER_ACCOUNT_KEY);
let userAccount = await getUserAccount();
if (!userAccount) {
userAccount = await fetchUserAccount();
setUserAccount(userAccount);
}
return Response.json({
userAccount,
});
}
import {uzeState, createStateKey} from "uzeful";
const EVENTS_KEY = createStateKey<string[]>("events", () => ["defaultEvent"]);
export default async function getUserInfo() {
const [getEvents] = uzeState(EVENTS_KEY);
let events = await getEvents();
events.push("newEvent");
console.log(events); // ["defaultEvent", "newEvent"]
...
}
Uze exposes SendableError
which provides a unified interface to handle errors. For the full
documentation: https://www.npmjs.com/package/sendable-error
import {SendableError} from "uzeful";
export default async function getUserInfo() {
const db = await uzeDatabase();
const user = await db.execute("...");
if (!user) {
throw new SendableError({
message: "User not found",
status: 404,
public: true,
code: "users/not-found"
});
}
...
}
Note: all errors are private by default. This means the response body will contain and obfuscated error. To make
an error public, set the public
property to true
.
uze
provides a wrapper around itty-router
's AutoRouter
to provide a simple way to define routes.
See the full documentation here: https://itty.dev/itty-router/routers/autorouter
import {createRouter} from "uzeful/router";
const router = createRouter()
.all("*", () => {
return Response.json({message: "Hello World"});
});