---
title: Hono
description: Use rest-rpc with Hono
---

## Install

```sh
pnpm add @rest-rpc/hono
```

## Usage

```ts
import { registerRoutes, router } from "@rest-rpc/hono";
import { Hono } from "hono";
import { api } from "./contract";

const app = new Hono();

const routes = router(api, {
	todos: {
		list() {
			return listTodos();
		},
		get({ id, context }) {
			const authorization = context.c.req.header("authorization");
			return getTodo(id, { authorization });
		},
		create({ title }) {
			return createTodo({ title });
		},
	},
});

registerRoutes(app, routes);

export default app;
```

## Framework Context

```ts
type HttpRouteHandlerContext<E extends Env = Env> = {
	c: Context<E>;
	signal: AbortSignal;
};

type WebSocketRouteHandlerContext<E extends Env = Env> = {
	c: Context<E>;
};
```

## Options

```ts
type RegisterRoutesOptions<TEnv extends Env = Env> = {
	errorHandlers?: ServerErrorHandlers<{
		c: Context<TEnv>;
		signal: AbortSignal;
	}>;
	parseBody?: HonoParseBody<TEnv>;
	webSocket?: HonoWebSocketOptions<TEnv>;
	middleware?: Array<(c: Context<TEnv>, next: Next, route: RouteDeclaration) => any>;
};
```

### Error Handlers

Request validation errors use `onRequestValidationError`. Response contract
validation errors use `onResponseValidationError` and default to a generic 500
response. Other unhandled route errors use `onUnhandledError`, or are re-thrown
when that hook is omitted or returns `undefined`.

```ts
registerRoutes(app, routes, {
	errorHandlers: {
		onRequestValidationError: ({ issues }) => ({
			status: 422,
			body: { code: "VALIDATION_ERROR", issues },
		}),
		onResponseValidationError: () => ({
			status: 500,
			body: { code: "INVALID_RESPONSE" },
		}),
		onUnhandledError: () => ({
			status: 500,
			body: { code: "INTERNAL_SERVER_ERROR" },
		}),
	},
});
```

### Body Parsing

```ts
registerRoutes(app, routes, {
	parseBody: ({ c }) => c.req.json(),
});
```

### WebSocket

```ts
import { upgradeWebSocket } from "hono/cloudflare-workers";

registerRoutes(app, routes, {
	webSocket: {
		upgradeWebSocket,
		beforeUpgrade: ({ context }) => {
			const authorization = context.c.req.header("authorization");
			return authorization ? undefined : { status: 401 };
		},
	},
});
```

### Middleware

```ts
registerRoutes(app, routes, {
	middleware: [
		async (c, next, route) => {
			const authorization = c.req.header("authorization");
			if (!authorization) {
				return c.json({ code: "UNAUTHORIZED" }, 401);
			}
			await next();
		},
	],
});
