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.

// 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

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

ParameterTypeDescription
name stringThe name of the header to configure.
value string | nullThe 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.

Method Syntax

api.invoke<Req, Res>(path, request?)

Parameters

ParameterTypeDescription
path stringThe API path to invoke.
request 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

ParameterTypeDescription
path 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

ParameterTypeDescription
path P extends ValidPaths<TPaths, "post">The API path to invoke.
body 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

ParameterTypeDescription
path P extends ValidPaths<TPaths, "put">The API path to invoke.
body 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

ParameterTypeDescription
path P extends ValidPaths<TPaths, "delete">The API path to invoke.
body 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

ParameterTypeDescription
path P extends ValidPaths<TPaths, "patch">The API path to invoke.
body 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

ParameterTypeDescription
path P extends ValidPaths<TPaths, "trace">The API path to invoke.
body 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');

// 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/123

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 {
// 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/456

See Also