# SurrealApi

The SurrealApi class provides methods for invoking user-defined API endpoints in SurrealDB.

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](https://github.com/surrealdb/surrealdb.js/blob/main/packages/sdk/src/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.

```ts
// 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`](/docs/reference/javascript/api/core/surreal-queryable.md#api) property on [`Surreal`](/docs/reference/javascript/api/core/surreal.md), [`SurrealSession`](/docs/reference/javascript/api/core/surreal-session.md), or [`SurrealTransaction`](/docs/reference/javascript/api/core/surreal-transaction.md):

```ts
// 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` {#pathdef}

Defines the HTTP methods available for an API path:

```ts
type PathDef = Partial<Record<HttpMethod, MethodDef>>;
type HttpMethod = "get" | "post" | "put" | "delete" | "patch" | "trace";
type MethodDef = [RequestBody, ResponseBody] | [];
```

### Example path definitions

```ts
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()` {#header}

Configure a header for all requests sent by this API instance. Useful for setting common headers like authentication tokens or content types.

```ts title="Method Syntax"
api.header(name, value)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>name</code> <label label="required" /></td>
            <td><code>string</code></td>
            <td>The name of the header to configure.</td>
        </tr>
        <tr>
            <td><code>value</code> <label label="required" /></td>
            <td><code>string | null</code></td>
            <td>The value to set, or <code>null</code> to remove the header.</td>
        </tr>
    </tbody>
</table>

#### Returns
`void`

#### Examples

```ts title="Set Custom Header"
api.header('X-API-Key', 'my-secret-key');
```

```ts title="Remove Header"
api.header('X-API-Key', null);
```

```ts title="Set Authorization Header"
api.header('Authorization', `Bearer ${token}`);
```

### `.invoke()` {#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()`](#get), [`.post()`](#post), etc.) for better type safety.

```ts title="Method Syntax"
api.invoke<T>(path, request?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>string</code></td>
            <td>The API path to invoke.</td>
        </tr>
        <tr>
            <td><code>request</code> <label label="optional" /></td>
            <td><code><a href="/docs/reference/javascript/api/types/#apirequest">ApiRequest</a>&lt;T&gt;</code></td>
            <td>The request configuration object.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<unknown>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the API response

#### Example
```ts
const result = await api.invoke('/custom', {
    method: 'post',
    body: { data: 'value' },
    headers: { 'X-Custom': 'header' },
    query: { filter: 'active' }
});
```

### `.get()` {#get}

Invoke a user-defined GET API endpoint.

```ts title="Method Syntax"
api.get(path)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>P extends ValidPaths&lt;TPaths, "get"&gt;</code></td>
            <td>The API path to invoke.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<void, ResponseBody>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the GET response

#### Examples

```ts title="Get All Users"
const users = await api.get("/users");
```

```ts title="Get Specific User"
const user = await api.get("/users/123");
```

### `.post()` {#post}

Invoke a user-defined POST API endpoint.

```ts title="Method Syntax"
api.post(path, body?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>P extends ValidPaths&lt;TPaths, "post"&gt;</code></td>
            <td>The API path to invoke.</td>
        </tr>
        <tr>
            <td><code>body</code> <label label="optional" /></td>
            <td><code>RequestBody&lt;TPaths, P, "post"&gt;</code></td>
            <td>The request body to send.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<RequestBody, ResponseBody>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the POST response

#### Example
```ts
const newUser = await api.post("/users", {
    name: "John Doe",
    email: "john@example.com"
});
```

### `.put()` {#put}

Invoke a user-defined PUT API endpoint.

```ts title="Method Syntax"
api.put(path, body?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>P extends ValidPaths&lt;TPaths, "put"&gt;</code></td>
            <td>The API path to invoke.</td>
        </tr>
        <tr>
            <td><code>body</code> <label label="optional" /></td>
            <td><code>RequestBody&lt;TPaths, P, "put"&gt;</code></td>
            <td>The request body to send.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<RequestBody, ResponseBody>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the PUT response

#### Example
```ts
const updated = await api.put("/users/123", {
    name: "John Smith",
    email: "john.smith@example.com"
});
```

### `.delete()` {#delete}

Invoke a user-defined DELETE API endpoint.

```ts title="Method Syntax"
api.delete(path, body?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>P extends ValidPaths&lt;TPaths, "delete"&gt;</code></td>
            <td>The API path to invoke.</td>
        </tr>
        <tr>
            <td><code>body</code> <label label="optional" /></td>
            <td><code>RequestBody&lt;TPaths, P, "delete"&gt;</code></td>
            <td>Optional request body.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<RequestBody, ResponseBody>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the DELETE response

#### Example
```ts
await api.delete("/users/123");
```

### `.patch()` {#patch}

Invoke a user-defined PATCH API endpoint.

```ts title="Method Syntax"
api.patch(path, body?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>P extends ValidPaths&lt;TPaths, "patch"&gt;</code></td>
            <td>The API path to invoke.</td>
        </tr>
        <tr>
            <td><code>body</code> <label label="optional" /></td>
            <td><code>RequestBody&lt;TPaths, P, "patch"&gt;</code></td>
            <td>The partial updates to apply.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<RequestBody, ResponseBody>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the PATCH response

#### Example
```ts
const updated = await api.patch("/users/123", {
    email: "newemail@example.com"
});
```

### `.trace()` {#trace}

Invoke a user-defined TRACE API endpoint.

```ts title="Method Syntax"
api.trace(path, body?)
```

#### Parameters
<table>
    <thead>
        <tr>
            <th>Parameter</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>path</code> <label label="required" /></td>
            <td><code>P extends ValidPaths&lt;TPaths, "trace"&gt;</code></td>
            <td>The API path to invoke.</td>
        </tr>
        <tr>
            <td><code>body</code> <label label="optional" /></td>
            <td><code>RequestBody&lt;TPaths, P, "trace"&gt;</code></td>
            <td>Optional request body.</td>
        </tr>
    </tbody>
</table>

#### Returns
[`ApiPromise<RequestBody, ResponseBody>`](/docs/reference/javascript/api/queries/api-promise.md) - A promise for the TRACE response

## Complete examples

### Basic API usage

```ts
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

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

```ts
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

```ts
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

```ts
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

```ts
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:

```ts
// 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:

```ts
// 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 organise related endpoints:

```ts
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

- [SurrealQueryable.api](/docs/reference/javascript/api/core/surreal-queryable.md#api) - Creating API instances
- [ApiPromise](/docs/reference/javascript/api/queries/api-promise.md) - API response handling
- [User-Defined APIs Guide](/docs/reference/query-language/statements/define/api.md) - Defining APIs in SurrealDB
