API Routes

Furin pages and Elysia API routes run in the same server process. There is no separate frontend dev server and no proxy layer required.

Define An API Plugin

src/api/index.ts
import { Elysia, t } from "elysia"

export const api = new Elysia({ prefix: "/api" })
  .get("/posts", async () => {
    return db.getAllPosts()
  })
  .post(
    "/posts",
    async ({ body }) => {
      return db.createPost(body)
    },
    {
      body: t.Object({
        title: t.String(),
        content: t.String(),
      }),
    }
  )

Mount It Before Furin

src/server.ts
import { Elysia } from "elysia"
import { furin } from "@teyik0/furin"
import { api } from "./api/index.ts"

const app = new Elysia()
  .use(api)
  .use(await furin({ pagesDir: "./src/pages" }))
  .listen(3000)

export type App = typeof app

Elysia instance order matters. Mount API plugins in the order you want them applied.

Typed Client Access

If you export typeof app, you can use Eden Treaty on the client side for end-to-end typing.

src/client.ts
import { treaty } from "@elysiajs/eden"
import type { App } from "./server.ts"

export const api = treaty<App>("localhost:3000")
src/pages/blog/index.tsx
import { api } from "@/client"
import { route } from "./_route"

export default route.page({
  loader: async () => {
    const { data } = await api.api.posts.get()
    return { posts: data ?? [] }
  },
  component: ({ posts }) => <PostList posts={posts} />,
})

Middleware And Guards

Use normal Elysia plugins, guards, and lifecycle hooks for auth, logging, rate limiting, or anything else:

ts
import { Elysia } from "elysia"
import { jwt } from "@elysiajs/jwt"

export const api = new Elysia({ prefix: "/api" })
  .use(jwt({ name: "jwt", secret: process.env.JWT_SECRET! }))
  .guard(
    {
      beforeHandle: async ({ cookie, jwt, set }) => {
        const user = await jwt.verify(cookie.auth.value)
        if (!user) {
          set.status = 401
          return "Unauthorized"
        }
      },
    },
    (app) => app.get("/me", ({ cookie, jwt }) => jwt.verify(cookie.auth.value))
  )

Comments