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.
// Define your API paths with types
type MyPaths = {
"/users": { get: [void, User[]] };
"/users/:id": { get: [void, User] };
"/users": { post: [CreateUserInput, User] };
};
// Access with type safety
const api = db.api<MyPaths>();
const users = await api.get("/users"); // Type: User[]Creating an API instance
API instances are created through the api property on Surreal, SurrealSession, or SurrealTransaction:
// Basic API access
const api = db.api();
// Type-safe API access
const api = db.api<MyPaths>();
// API with path prefix
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 = {
// GET endpoint with no request body, returns User[]
"/users": {
get: [void, User[]];
post: [CreateUserRequest, User];
};
// Dynamic path parameters
[K: `/users/${string}`]: {
get: [void, User];
put: [UpdateUserRequest, User];
delete: [void, void];
};
// POST endpoint with request/response bodies
"/auth/login": {
post: [{ email: string; password: string }, { token: string }];
};
};Methods
.header()
Configure a header for all requests sent by this API instance. Useful for setting common headers like authentication tokens or content types.
api.header(name, value)Parameters
Parameter | Type | Description |
|---|---|---|
name | string | The name of the header to configure. |
value | string | null | The value to set, or nullto remove the header. |
Returns
void
Examples
api.header('X-API-Key', 'my-secret-key');api.header('X-API-Key', null);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.
!NOTE: Tip
Prefer using method-specific functions (.get(),.post(), etc.) for better type safety.
api.invoke<T>(path, request?)Parameters
Parameter | Type | Description |
|---|---|---|
path | string | The API path to invoke. |
request | ApiRequest T | The request configuration object. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - 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.
api.get(path)Parameters
Parameter | Type | Description |
|---|---|---|
path | P extends ValidPaths<TPaths, "get"> | The API path to invoke. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - A promise for the GET response
Examples
const users = await api.get("/users");const user = await api.get("/users/123"); .post()
Invoke a user-defined POST API endpoint.
api.post(path, body?)Parameters
Parameter | Type | Description |
|---|---|---|
path | P extends ValidPaths<TPaths, "post"> | The API path to invoke. |
body | RequestBody<TPaths, P, "post"> | The request body to send. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - 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.
api.put(path, body?)Parameters
Parameter | Type | Description |
|---|---|---|
path | P extends ValidPaths<TPaths, "put"> | The API path to invoke. |
body | RequestBody<TPaths, P, "put"> | The request body to send. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - 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.
api.delete(path, body?)Parameters
Parameter | Type | Description |
|---|---|---|
path | P extends ValidPaths<TPaths, "delete"> | The API path to invoke. |
body | RequestBody<TPaths, P, "delete"> | Optional request body. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - A promise for the DELETE response
Example
await api.delete("/users/123"); .patch()
Invoke a user-defined PATCH API endpoint.
api.patch(path, body?)Parameters
Parameter | Type | Description |
|---|---|---|
path | P extends ValidPaths<TPaths, "patch"> | The API path to invoke. |
body | RequestBody<TPaths, P, "patch"> | The partial updates to apply. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - 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.
api.trace(path, body?)Parameters
Parameter | Type | Description |
|---|---|---|
path | P extends ValidPaths<TPaths, "trace"> | The API path to invoke. |
body | RequestBody<TPaths, P, "trace"> | Optional request body. |
Returns
[`ApiPromise`](/docs/languages/javascript/api/queries/api-promise) - 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');
// Get API instance
const api = db.api();
// Make API calls
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
// Define your API contract
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];
};
};
// Create type-safe API instance
const api = db.api<ApiPaths>();
// All calls are type-checked
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"
});Using headers
const api = db.api();
// Set authentication header
const token = await login();
api.header('Authorization', `Bearer ${token}`);
// All subsequent requests include the header
const protected Data = await api.get('/protected-endpoint');
// Remove header
api.header('Authorization', null);API with prefix
type UserPaths = {
"/": { get: [void, User[]] };
[K: `/${string}`]: {
get: [void, User];
put: [UpdateUserRequest, User];
delete: [void, void];
};
};
// Create API with prefix
const usersApi = db.api<UserPaths>("/users");
// Calls are prefixed automatically
const all Users = await usersApi.get("/"); // GET /users/
const user = await usersApi.get("/123"); // GET /users/123
const updated = await usersApi.put("/123", data); // PUT /users/123Error 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 {
// API calls within transaction
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:
// Good: Type-safe
type MyApi = {
"/users": { get: [void, User[]] };
};
const api = db.api<MyApi>();
// Avoid: Untyped
const api = db.api();2. Reuse API instances
Create and reuse API instances rather than creating new ones for each call:
// Good: Reuse instance
const api = db.api();
await api.get('/users');
await api.get('/posts');
// Avoid: Creating multiple instances
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"); // GET /users/123
await postsApi.get("/456"); // GET /posts/456See also
SurrealQueryable.api - Creating API instances
ApiPromise - API response handling
User-Defined APIs Guide - Defining APIs in SurrealDB