Skip to content

Eden Treaty

Eden Treaty is an object representation used to interact with a server and features type safety, auto-completion, and error handling.

A path becomes properties on the client, followed by its HTTP method. api.hi.get() calls GET /hi and returns Hi Elysia.

Here, passing the instance directly keeps the call in the same process. No listening server is needed.

import { Elysia } from 'elysia'
import { treaty } from '@elysia/eden'
const app = new Elysia().get('/hi', 'Hi Elysia')
const api = treaty(app)
const { data, error } = await api.hi.get()
if (error) throw error
console.log(data)

Call a dynamic segment with an object containing its parameter name. api.id({ id: 1895 }).get() calls GET /id/1895.

TypeScript knows which parameter the route accepts.

import { Elysia } from 'elysia'
import { treaty } from '@elysia/eden'
const app = new Elysia()
.get('/hi', 'Hi Elysia')
.get('/id/:id', ({ params: { id } }) => id)
const api = treaty(app)
const { data, error } = await api.id({ id: 1895 }).get()
if (error) throw error
console.log(data)

Pass a body to a method such as post. The route’s schema guides the client: this request needs a numeric id and a string name.

The server returns the same object. Check error before using data.

import { Elysia, t } from 'elysia'
import { treaty } from '@elysia/eden'
const app = new Elysia()
.get('/hi', 'Hi Elysia')
.get('/id/:id', ({ params: { id } }) => id)
.post('/mirror', {
body: t.Object({ id: t.Number(), name: t.String() })
}, ({ body }) => body)
const api = treaty(app)
const { data, error } = await api.mirror.post({ id: 1895, name: 'Skadi' })
if (error) throw error
console.log(data)

To call a separately running server, first export your existing Elysia server’s type:

server.ts
import { Elysia, t } from 'elysia'
const app = new Elysia()
.get('/hi', () => 'Hi Elysia')
.get('/id/:id', ({ params: { id } }) => id)
.post('/mirror', {
body: t.Object({
id: t.Number(),
name: t.String()
})
}, ({ body }) => body)
.listen(3000)
export type App = typeof app

Then import the server type and consume the Elysia API on the client:

client.ts

client.ts
import { treaty } from '@elysia/eden'
import type { App } from './server'
const app = treaty<App>('localhost:3000')
// response type: 'Hi Elysia'
const { data, error } = await app.hi.get()

An HTTP path is a resource indicator for a file system tree.

A file system consists of multiple levels of folders, for example:

  • /documents/elysia
  • /documents/kalpas
  • /documents/kelvin

Each level is separated by / (slash) and a name.

However, in JavaScript, instead of using ”/” (slash), we use ”.” (dot) to access deeper resources.

Eden Treaty turns an Elysia server into a tree-like file system that can be accessed from the JavaScript frontend instead.

PathTreaty
/
/hi.hi
/deep/nested.deep.nested

Combined with the HTTP method, we can interact with the Elysia server.

PathMethodTreaty
/GET.get()
/hiGET.hi.get()
/deep/nestedGET.deep.nested.get()
/deep/nestedPOST.deep.nested.post()

Dynamic path parameters need a name as well as a value. For an api client whose server registers /item/:name, use a function call to identify the parameter.

// Unclear what the value is supposed to represent?
api.item['skadi'].get()

This property-access form belongs to the legacy Eden Treaty 1 client; in Eden Treaty 2 it is a type error.

To handle this, we can specify a dynamic path using a function to provide a key value instead.

// Clear that the value is dynamic and the path is 'name'
api.item({ name: 'Skadi' }).get()
PathTreaty
/item.item
/item/:name.item({ name: 'Skadi' })
/item/:name/id.item({ name: 'Skadi' }).id

Type to search the documentation.

    Up arrowDown arrow to navigateEnter to selectEscape to close