SurrealApi
The SurrealApi class exposes methods to interact with user-defined API endpoints in SurrealDB. It provides type-safe HTTP-style methods (GET, POST, PUT, DELETE, PATCH, TRACE) for invoking custom database APIs.
Source: api/api.ts
Overview
SurrealApi allows you to access custom API endpoints defined in your SurrealDB database. The class supports type-safe API definitions for better development experience.
type MyPaths = {
"/users": { get: [void, User[]] };
"/users/:id": { get: [void, User] };
"/users": { post: [CreateUserInput, User] };
};
const api = db.api<MyPaths>();
const users = await api.get("/users");
Creating an API Instance
API instances are created through the api property on Surreal, SurrealSession, or SurrealTransaction:
const api = db.api();
const api = db.api<MyPaths>();
const usersApi = db.api<MyPaths>("/users");
Type Definitions
PathDef
Defines the HTTP methods available for an API path:
type PathDef = Partial<Record<HttpMethod, MethodDef>>;
type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "trace";
type MethodDef = [RequestBody, ResponseBody] | [];
Example Path Definitions
type MyApiPaths = {
"/users": {
get: [void, User[]];
post: [CreateUserRequest, User];
};
[K: `/users/${string}`]: {
get: [void, User];
put: [UpdateUserRequest, User];
delete: [void, void];
};
"/auth/login": {
post: [{ email: string; password: string }, { token: string }];
};
};
Methods
Configure a header for all requests sent by this API instance. Useful for setting common headers like authentication tokens or content types.
Method Syntax
api.header(name, value)
Parameters
| Parameter | Type | Description |
|---|
name required | string | The name of the header to configure. |
value required | string | null | The value to set, or null to remove the header. |
Returns
void
Examples
Set Custom Header
api.header('X-API-Key', 'my-secret-key');
Remove Header
api.header('X-API-Key', null);
Set Authorization Header
api.header('Authorization', `Bearer ${token}`);
.invoke()
Invoke a user-defined API with a custom request object. This is the generic method used by all HTTP method-specific functions.
Prefer using method-specific functions (.get(), .post(), etc.) for better type safety.
Method Syntax
api.invoke<Req, Res>(path, request?)
Parameters
| Parameter | Type | Description |
|---|
path required | string | The API path to invoke. |
request optional | ApiRequest<Req> | The request configuration object. |
Returns
ApiPromise<Req, Res> - A promise for the API response
Example
const result = await api.invoke('/custom', {
method: 'post',
body: { data: 'value' },
headers: { 'X-Custom': 'header' },
query: { filter: 'active' }
});
.get()
Invoke a user-defined GET API endpoint.
Method Syntax
api.get(path)
Parameters
| Parameter | Type | Description |
|---|
path required | P extends ValidPaths<TPaths, “get”> | The API path to invoke. |
Returns
ApiPromise<void, ResponseBody> - A promise for the GET response
Examples
Get All Users
const users = await api.get("/users");
Get Specific User
const user = await api.get("/users/123");
.post()
Invoke a user-defined POST API endpoint.
Method Syntax
api.post(path, body?)
Parameters
| Parameter | Type | Description |
|---|
path required | P extends ValidPaths<TPaths, “post”> | The API path to invoke. |
body optional | RequestBody<TPaths, P, “post”> | The request body to send. |
Returns
ApiPromise<RequestBody, ResponseBody> - A promise for the POST response
Example
const newUser = await api.post("/users", {
name: "John Doe",
email: "john@example.com"
});
.put()
Invoke a user-defined PUT API endpoint.
Method Syntax
api.put(path, body?)
Parameters
| Parameter | Type | Description |
|---|
path required | P extends ValidPaths<TPaths, “put”> | The API path to invoke. |
body optional | RequestBody<TPaths, P, “put”> | The request body to send. |
Returns
ApiPromise<RequestBody, ResponseBody> - A promise for the PUT response
Example
const updated = await api.put("/users/123", {
name: "John Smith",
email: "john.smith@example.com"
});
.delete()
Invoke a user-defined DELETE API endpoint.
Method Syntax
api.delete(path, body?)
Parameters
| Parameter | Type | Description |
|---|
path required | P extends ValidPaths<TPaths, “delete”> | The API path to invoke. |
body optional | RequestBody<TPaths, P, “delete”> | Optional request body. |
Returns
ApiPromise<RequestBody, ResponseBody> - A promise for the DELETE response
Example
await api.delete("/users/123");
.patch()
Invoke a user-defined PATCH API endpoint.
Method Syntax
api.patch(path, body?)
Parameters
| Parameter | Type | Description |
|---|
path required | P extends ValidPaths<TPaths, “patch”> | The API path to invoke. |
body optional | RequestBody<TPaths, P, “patch”> | The partial updates to apply. |
Returns
ApiPromise<RequestBody, ResponseBody> - A promise for the PATCH response
Example
const updated = await api.patch("/users/123", {
email: "newemail@example.com"
});
.trace()
Invoke a user-defined TRACE API endpoint.
Method Syntax
api.trace(path, body?)
Parameters
| Parameter | Type | Description |
|---|
path required | P extends ValidPaths<TPaths, “trace”> | The API path to invoke. |
body optional | RequestBody<TPaths, P, “trace”> | Optional request body. |
Returns
ApiPromise<RequestBody, ResponseBody> - A promise for the TRACE response
Complete Examples
Basic API Usage
import { Surreal } from 'surrealdb';
const db = new Surreal();
await db.connect('ws://localhost:8000');
const api = db.api();
const users = await api.get('/users');
const user = await api.get('/users/123');
const created = await api.post('/users', {
name: 'New User',
email: 'user@example.com'
});
Type-Safe API
type ApiPaths = {
"/users": {
get: [void, User[]];
post: [CreateUserRequest, User];
};
[K: `/users/${string}`]: {
get: [void, User];
put: [UpdateUserRequest, User];
delete: [void, void];
};
"/auth/login": {
post: [LoginRequest, LoginResponse];
};
};
const api = db.api<ApiPaths>();
const users: User[] = await api.get("/users");
const user: User = await api.get("/users/123");
const newUser: User = await api.post("/users", {
name: "Alice",
email: "alice@example.com"
});
const api = db.api();
const token = await login();
api.header('Authorization', `Bearer ${token}`);
const protected Data = await api.get('/protected-endpoint');
api.header('Authorization', null);
API with Prefix
type UserPaths = {
"/": { get: [void, User[]] };
[K: `/${string}`]: {
get: [void, User];
put: [UpdateUserRequest, User];
delete: [void, void];
};
};
const usersApi = db.api<UserPaths>("/users");
const all Users = await usersApi.get("/");
const user = await usersApi.get("/123");
const updated = await usersApi.put("/123", data);
Error Handling
const api = db.api();
try {
const user = await api.get('/users/999');
} catch (error) {
if (error instanceof ResponseError) {
console.error('API error:', error.message);
console.error('Status code:', error.code);
} else {
console.error('Unexpected error:', error);
}
}
With Transaction
const txn = await db.beginTransaction();
try {
const api = txn.api();
const user = await api.post('/users', userData);
const profile = await api.post('/profiles', {
userId: user.id,
...profileData
});
await txn.commit();
} catch (error) {
await txn.cancel();
throw error;
}
Best Practices
1. Define API Types
Always define types for your API paths for better developer experience:
type MyApi = {
"/users": { get: [void, User[]] };
};
const api = db.api<MyApi>();
const api = db.api();
2. Reuse API Instances
Create and reuse API instances rather than creating new ones for each call:
const api = db.api();
await api.get('/users');
await api.get('/posts');
await db.api().get('/users');
await db.api().get('/posts');
3. Use Prefixes for Namespacing
Use path prefixes to organize related endpoints:
const usersApi = db.api("/users");
const postsApi = db.api("/posts");
await usersApi.get("/123");
await postsApi.get("/456");
See Also