• Start

Languages

/

JavaScript

/

API Reference

/

Query builders

ApiPromise

ApiPromise provides methods for executing user-defined API calls.

The ApiPromise class provides an interface for executing user-defined API endpoint calls. It extends Promise, allowing you to await it directly or configure the response handling.

Returned by: Methods on SurrealApi

Source: query/api.ts

  • Req - The request body type

  • Res - The response body type

  • V - Boolean for value-only response (default: false)

  • J - Boolean indicating if result is JSON (default: false)

Configure the query to return the result as a JSON string.

Method Syntax
apiPromise.json()

`ApiPromise` - Promise returning JSON string

const jsonString = await db.api().get('/users').json();
console.log(typeof jsonString); // 'string'

Append a header to the API request.

Method Syntax
apiPromise.header(name, value)

Parameter

Type

Description

namestring

The header name.

valuestring

The header value.

`ApiPromise` - Chainable promise

const result = await db.api().get('/users')
    .header('X-Custom-Header', 'value')
    .header('Authorization', 'Bearer token');

Return only the response body value, without the wrapper object.

Method Syntax
apiPromise.value()

`ApiPromise` - Promise returning only the value

Without .value()
const response = await db.api().get('/users');
console.log(response.body); // The actual data
console.log(response.status); // HTTP status
console.log(response.headers); // Response headers
With .value()
const users = await db.api().get('/users').value();
console.log(users); // Direct access to user array

Compile the query into a BoundQuery.

Method Syntax
apiPromise.compile()

`BoundQuery` - The compiled query

Stream results as they are received.

Method Syntax
apiPromise.stream()

`AsyncIterable` - Async iterable of response frames

Append a URL query parameter to the API request.

Method Syntax
apiPromise.query(name, value)

Parameter

Type

Description

namestring

The query parameter name.

valuestring

The query parameter value.

`ApiPromise` - A new ApiPromise with the query parameter appended

const result = await db.api().get('/users')
    .query('filter', 'active')
    .query('sort', 'created_at')
    .value();
interface ApiResponse<T> {
    body?: T;
    headers?: Record<string, string>;
    status?: number;
}
// Returns Res directly instead of ApiResponse<Res>
import { Surreal } from 'surrealdb';

const db = new Surreal();
await db.connect('ws://localhost:8000');

const api = db.api();

// GET request
const users = await api.get('/users').value();

// POST request
const newUser = await api.post('/users', {
    name: 'John Doe',
    email: 'john@example.com'
}).value();

// PUT request
const updated = await api.put('/users/123', {
    name: 'John Smith'
}).value();

// DELETE request
await api.delete('/users/123').value();
const response = await db.api().get('/users');

console.log('Status:', response.status);
console.log('Headers:', response.headers);
console.log('Body:', response.body);

if (response.status === 200) {
    console.log('Success:', response.body);
}
const result = await db.api().post('/protected', data)
    .header('Authorization', `Bearer ${token}`)
    .header('X-API-Version', '2.0')
    .value();
interface User {
    id: string;
    name: string;
    email: string;
}

interface CreateUserRequest {
    name: string;
    email: string;
    password: string;
}

type ApiPaths = {
    "/users": {
        get: [void, User[]];
        post: [CreateUserRequest, User];
    };
};

const api = db.api<ApiPaths>();

// Type-safe calls
const users: User[] = await api.get('/users').value();
const newUser: User = await api.post('/users', {
    name: 'Alice',
    email: 'alice@example.com',
    password: 'secure'
}).value();
try {
    const user = await db.api().get('/users/999').value();
} catch (error) {
    if (error instanceof UnsuccessfulApiError) {
        console.error('API error:', error.response);
        console.error('Status:', error.response.status);
        console.error('Message:', error.response.body);
    }
}
async function fetchPage(page: number, pageSize: number) {
    return db.api().get(`/users?page=${page}&limit=${pageSize}`).value();
}

const page1 = await fetchPage(1, 20);
const page2 = await fetchPage(2, 20);
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('name', 'profile-picture');

const result = await db.api().post('/upload', formData)
    .header('Content-Type', 'multipart/form-data')
    .value();
// Login
const loginResult = await db.api().post('/auth/login', {
    email: 'user@example.com',
    password: 'password123'
}).value();

const { access_token } = loginResult;

// Use token for subsequent requests
const api = db.api();
api.header('Authorization', `Bearer ${access_token}`);

const profile = await api.get('/profile').value();
const orders = await api.get('/orders').value();
const api = db.api();

// Check if resource exists
const checkResponse = await api.get('/users/123');

if (checkResponse.status === 404) {
    // Create if doesn't exist
    await api.post('/users/123', userData).value();
} else {
    // Update if exists
    await api.put('/users/123', userData).value();
}
const api = db.api();

const promises = userIds.map(id =>
    api.get(`/users/${id}`).value()
);

const users = await Promise.all(promises);
console.log(`Fetched ${users.length} users`);
const response = await db.api().get('/users');

const transformed = {
    data: response.body,
    timestamp: new Date(),
    status: response.status,
    cached: response.headers?.['X-Cache'] === 'HIT'
};
async function apiWithRetry(
    apiCall: () => Promise<any>,
    maxRetries = 3
) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            return await apiCall();
        } catch (error) {
            if (i === maxRetries - 1) throw error;
            await new Promise(r => setTimeout(r, 1000 * (i + 1)));
        }
    }
}

const result = await apiWithRetry(() =>
    db.api().get('/unstable-endpoint').value()
);
// Build query params manually
const params = new URLSearchParams({
    filter: 'active',
    sort: 'created_at',
    order: 'desc'
});

const users = await db.api().get(`/users?${params}`).value();
// Both use the same connection
const db = new Surreal();
await db.connect('ws://localhost:8000');

// Regular query (via WebSocket/HTTP RPC)
const users1 = await db.select(new Table('users'));

// API endpoint (via defined API routes)
const users2 = await db.api().get('/users').value();

// Both work, but API endpoints allow custom logic
const response = await db.api().get('/users');

console.log('Content-Type:', response.headers?.['Content-Type']);
console.log('Cache-Control:', response.headers?.['Cache-Control']);
console.log('X-Custom:', response.headers?.['X-Custom-Header']);
// Good: Type-safe API
type MyApi = {
    "/users": { get: [void, User[]] };
};
const api = db.api<MyApi>();

// Avoid: Untyped
const api = db.api();
// Good: Direct value access
const users = await api.get('/users').value();

// More verbose:
const response = await api.get('/users');
const users = response.body;
// Good: Specific error handling
try {
    const result = await api.get('/users').value();
} catch (error) {
    if (error instanceof UnsuccessfulApiError) {
        // Handle API errors
    }
}

Was this page helpful?