DEV Community

Alex Spinov
Alex Spinov

Posted on

Elysia Has a Free API You Should Know About

Elysia is the fastest Bun web framework with end-to-end type safety. Its API is elegant, fully typed, and blazingly fast — handling 2.5M req/sec on a single thread.

Basic API

import { Elysia, t } from "elysia"

const app = new Elysia()
  .get("/", () => "Hello Elysia")
  .get("/users", async () => {
    return db.user.findMany()
  })
  .get("/users/:id", async ({ params: { id } }) => {
    return db.user.findUnique({ where: { id } })
  })
  .post("/users", async ({ body }) => {
    return db.user.create({ data: body })
  }, {
    body: t.Object({
      name: t.String({ minLength: 2 }),
      email: t.String({ format: "email" })
    })
  })
  .listen(3000)

console.log(`Running at ${app.server?.hostname}:${app.server?.port}`)
Enter fullscreen mode Exit fullscreen mode

Type-Safe Validation with TypeBox

import { Elysia, t } from "elysia"

const app = new Elysia()
  .post("/products", ({ body }) => {
    // body is fully typed: { name: string, price: number, tags: string[] }
    return createProduct(body)
  }, {
    body: t.Object({
      name: t.String(),
      price: t.Number({ minimum: 0 }),
      tags: t.Array(t.String())
    }),
    response: t.Object({
      id: t.String(),
      name: t.String(),
      price: t.Number(),
      createdAt: t.String()
    })
  })
Enter fullscreen mode Exit fullscreen mode

Plugin System

const authPlugin = new Elysia({ name: "auth" })
  .derive(({ headers }) => {
    const token = headers.authorization?.replace("Bearer ", "")
    return { userId: token ? verifyToken(token) : null }
  })
  .macro(({ onBeforeHandle }) => ({
    isAuth(enabled: boolean) {
      if (enabled) {
        onBeforeHandle(({ userId, error }) => {
          if (!userId) return error(401, "Unauthorized")
        })
      }
    }
  }))

const app = new Elysia()
  .use(authPlugin)
  .get("/public", () => "Anyone can see this")
  .get("/private", ({ userId }) => `Hello user ${userId}`, {
    isAuth: true
  })
Enter fullscreen mode Exit fullscreen mode

Groups & Guards

const app = new Elysia()
  .group("/api/v1", (app) =>
    app
      .get("/health", () => ({ status: "ok" }))
      .guard({
        headers: t.Object({
          authorization: t.String()
        })
      }, (app) =>
        app
          .get("/users", () => db.user.findMany())
          .get("/posts", () => db.post.findMany())
          .delete("/users/:id", ({ params }) => db.user.delete({ where: { id: params.id } }))
      )
  )
Enter fullscreen mode Exit fullscreen mode

WebSocket

const app = new Elysia()
  .ws("/chat", {
    body: t.Object({
      message: t.String()
    }),
    open(ws) {
      ws.subscribe("chat-room")
    },
    message(ws, { message }) {
      ws.publish("chat-room", { from: ws.id, message })
    },
    close(ws) {
      ws.unsubscribe("chat-room")
    }
  })
Enter fullscreen mode Exit fullscreen mode

Eden Treaty — End-to-End Type Safety

// Client-side — fully typed from server definition!
import { treaty } from "@elysiajs/eden"
import type { App } from "./server"

const api = treaty<App>("localhost:3000")

// Fully typed — autocomplete works!
const { data } = await api.users.get()
const { data: user } = await api.users({ id: "123" }).get()
const { data: created } = await api.users.post({
  name: "John",
  email: "john@example.com"
})
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • 2.5M req/sec — fastest Bun framework
  • End-to-end type safety with Eden Treaty
  • TypeBox validation with automatic typing
  • Plugin system with derive and macros
  • Guards for grouped middleware
  • WebSocket with typed messages

Explore Elysia docs for the complete API.


Building web scrapers or data pipelines? Check out my Apify actors for ready-made solutions, or email spinov001@gmail.com for custom development.

Top comments (0)