Skip to content

Elysia Data Provider

The @svadmin/elysia package provides a DataProvider that connects to Elysia backends following CRUD conventions, with optional end-to-end type inference via Eden Treaty.

Terminal window
bun add @svadmin/elysia
import { createElysiaDataProvider } from '@svadmin/elysia';
const dataProvider = createElysiaDataProvider({
apiUrl: 'http://localhost:3000',
});
const dataProvider = createElysiaDataProvider({
apiUrl: 'http://localhost:3000',
headers: () => ({
Authorization: `Bearer ${getToken()}`,
}),
});

The provider expects standard RESTful routes:

OperationMethodRouteRequestResponse
ListGET/resource?_page=1&_limit=10query params{ items: T[], total: number }
Get oneGET/resource/:idT
CreatePOST/resourceJSON bodyT
UpdatePATCH/resource/:idJSON bodyT
DeleteDELETE/resource/:idT
ParamFormatExample
Pagination_page, _limit?_page=1&_limit=10
Sorting_sort, _order?_sort=name&_order=asc
Filteringfield_operator?status_eq=active&name_contains=foo

Filters are appended as query params using field_operator=value format:

?status_eq=active → status = 'active'
?price_gte=100 → price >= 100
?name_contains=widget → name LIKE '%widget%'
?category_in=1,2,3 → category IN (1, 2, 3)

The main advantage of @svadmin/elysia is auto-inferring ResourceTypeMap from your Elysia server:

server.ts
import { Elysia } from 'elysia';
const app = new Elysia()
.get('/posts', () => db.posts.findMany())
.get('/posts/:id', ({ params }) => db.posts.findUnique({ where: { id: params.id } }))
.post('/posts', ({ body }) => db.posts.create({ data: body }))
.patch('/posts/:id', ({ params, body }) => db.posts.update({ where: { id: params.id }, data: body }))
.delete('/posts/:id', ({ params }) => db.posts.delete({ where: { id: params.id } }));
export type App = typeof app;
resource-types.d.ts
import type { InferResourceMap } from '@svadmin/elysia';
import type { App } from './server';
declare module '@svadmin/core' {
interface ResourceTypeMap extends InferResourceMap<App> {}
}

Now all hooks automatically know your resource names and data shapes:

// Resource name is constrained at compile time
useList({ resource: 'posts' }); // ✅
useList({ resource: 'postz' }); // ❌ TypeScript error
// Data types auto-inferred
const query = useOne({ resource: 'posts', id: 1 });
query.data?.data.title; // string ✓ — no manual type annotation needed
interface ElysiaDataProviderOptions {
/** Base API URL, e.g. 'http://localhost:3000' */
apiUrl: string;
/** Static headers or a function returning headers */
headers?: Record<string, string> | (() => Record<string, string>);
}

The provider also supports batch operations:

  • getMany — fetches multiple records by ID via ?ids=1,2,3
  • createMany — sequential POST calls
  • updateMany — sequential PATCH calls
  • deleteMany — sequential DELETE calls
  • custom — arbitrary HTTP requests
Feature@svadmin/simple-rest@svadmin/elysia
Type inferenceManualAuto via Eden Treaty
Response format{ data: T[] }{ items: T[], total: number }
Filter formatHeader-basedQuery param field_operator
AuthJWT/Cookie built-inVia headers option
DependenciesZeroZero (Eden Treaty optional)