Spoosh
Integrations

Hono

Type-safe API client from your Hono server

The @spoosh/hono package transforms your Hono app type into Spoosh's ApiSchema format, giving you end-to-end type safety.

For proper type inference, your Hono routes must follow the Hono RPC guide. Chain your routes directly on the app instance and export the app type.

Installation

npm install @spoosh/hono

Setup

Server (Hono)

Define your Hono routes and export the app type:

server.ts
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";

const app = new Hono()
  .basePath("/api")
  .get("/posts", (c) => {
    return c.json([
      { id: 1, title: "Hello World" },
      { id: 2, title: "Getting Started" },
    ]);
  })
  .post("/posts", zValidator("json", z.object({ title: z.string() })), (c) => {
    const body = c.req.valid("json");
    return c.json({ id: 3, title: body.title });
  })
  .get("/posts/:id", (c) => {
    const id = c.req.param("id");
    return c.json({ id: Number(id), title: "Post Title" });
  })
  .delete("/posts/:id", (c) => {
    return c.json({ success: true });
  });

// Export the app type for client usage
export type AppType = typeof app;

Client (Spoosh)

Use HonoToSpoosh to convert the Hono type:

client.ts
import { createSpoosh } from "@spoosh/core";
import { createReactSpoosh } from "@spoosh/react";
import type { HonoToSpoosh } from "@spoosh/hono";
import type { AppType } from "./server";

type ApiSchema = HonoToSpoosh<AppType>;

const spoosh = createSpoosh<ApiSchema>({
  baseUrl: "http://localhost:3000/api",
  plugins: [],
});

export const { useRead, useWrite } = createReactSpoosh(spoosh);

Usage

All API calls are fully typed:

// GET /api/posts
const { data: posts } = await api.posts.$get();
// posts: { id: number; title: string }[]

// POST /api/posts
const { data: newPost } = await api.posts.$post({
  body: { title: "New Post" }, // body is typed
});
// newPost: { id: number; title: string }

// GET /api/posts/1
const { data: post } = await api.posts[1].$get();
// post: { id: number; title: string }

// DELETE /api/posts/1
await api.posts[1].$delete();

Type Mapping

HonoSpoosh
c.json(data)Response data type
zValidator("json", schema)Request body type
zValidator("query", schema)Query params type
zValidator("form", schema)Form data type
/posts/:idposts._ (dynamic segment)

Path Parameters

Dynamic segments (:id, :slug, etc.) are converted to _ in the schema:

// Hono route: /users/:userId/posts/:postId
// Spoosh path: api.users[userId].posts[postId].$get()

On this page