SurrealDB
SurrealDB Docs Logo

Enter a search query

Navigation

ApiPromise<Req, Res, V, J>

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

Type Parameters

  • 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)

Configuration Methods

.json()

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

Method Syntax
apiPromise.json()

Returns

ApiPromise<Req, Res, V, true> - Promise returning JSON string

Example

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)

Parameters

ParameterTypeDescription
name requiredstringThe header name.
value requiredstringThe header value.

Returns

ApiPromise<Req, Res, V, J> - Chainable promise

Example

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

.value()

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

Method Syntax
apiPromise.value()

Returns

ApiPromise<Req, Res, true, J> - Promise returning only the value

Examples

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

Response Structure

Default Response (without .value())

interface ApiResponse<T> { body?: T; headers?: Record<string, string>; status?: number; }

Value Response (with .value())

// Returns Res directly instead of ApiResponse<Res>

Complete Examples

Basic API Calls

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();

With Full Response

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); }

Custom Headers

const result = await db.api().post('/protected', data) .header('Authorization', `Bearer ${token}`) .header('X-API-Version', '2.0') .value();

Type-Safe API Calls

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();

Error Handling

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); } }

Pagination

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);

File Upload

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();

Authentication Flow

// 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();

Conditional Requests

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(); }

Batch Operations

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`);

Response Transformation

const response = await db.api().get('/users'); const transformed = { data: response.body, timestamp: new Date(), status: response.status, cached: response.headers?.['X-Cache'] === 'HIT' };

Retry Pattern

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() );

Query Parameters

// Build query params manually const params = new URLSearchParams({ filter: 'active', sort: 'created_at', order: 'desc' }); const users = await db.api().get(`/users?${params}`).value();

WebSocket vs API Endpoints

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

Response Headers

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']);

Best Practices

1. Use Type Definitions

// Good: Type-safe API type MyApi = { "/users": { get: [void, User[]] }; }; const api = db.api<MyApi>(); // Avoid: Untyped const api = db.api();

2. Use .value() for Simpler Code

// Good: Direct value access const users = await api.get('/users').value(); // More verbose: const response = await api.get('/users'); const users = response.body;

3. Handle Errors Gracefully

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

See Also