Skip to main content

REST Client

The REST client provides typed HTTP requests to the Heimdall API.

apiRequest

Make an authenticated REST request. The first argument is always an ApiClientConfig — pass getApiConfig() from @/lib/api.

import { getApiConfig, apiRequest } from "@/lib/api";
import type { ApiResponse } from "@/lib/api";

const response: ApiResponse<User> = await apiRequest<User>(getApiConfig(), "/v1/users/123");

Parameters

ParameterTypeRequiredDescription
configApiClientConfigYesAPI client config (baseUrl, optional systemApiKey) — use getApiConfig()
endpointstringYesAPI endpoint (e.g., /v1/users/123)
optionsApiRequestOptionsNoRequest options

Options

interface ApiRequestOptions {
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
body?: unknown;
headers?: Record<string, string>;
accessToken?: string;
userAgent?: string;
clientIp?: string;
sourceService?: string;
}
OptionTypeDefaultDescription
methodstring"GET"HTTP method
bodyunknown-Request body (auto-serialized to JSON)
headersRecord<string, string>-Additional headers
accessTokenstring-Override auth token
userAgentstring-Original client User-Agent (forwarded as X-Original-User-Agent)
clientIpstring-Original client IP (forwarded as X-Forwarded-For)
sourceServicestring-Source service (sent as X-Source-Service)

Response

interface ApiResponse<T> {
data?: T;
error?: string;
status: number;
}

Examples

GET Request

import { getApiConfig, apiRequest } from "@/lib/api";

const response = await apiRequest<UserProfile>(getApiConfig(), "/v1/users/123/profile");

if (response.error) {
console.error("Error:", response.error);
return;
}

console.log("User:", response.data);

POST Request

const response = await apiRequest<CreateUserResponse>(getApiConfig(), "/v1/users", {
method: "POST",
body: {
name: "John Doe",
},
});

if (response.status === 201) {
console.log("User created:", response.data);
}

PUT Request with Auth Override

const response = await apiRequest<void>(getApiConfig(), "/v1/users/123", {
method: "PUT",
body: { name: "New Name" },
accessToken: userAccessToken,
});

DELETE Request

const response = await apiRequest<void>(getApiConfig(), "/v1/users/123", {
method: "DELETE",
});

if (response.status === 204) {
console.log("User deleted");
}

Error Handling

The client handles errors gracefully and returns them in the response:

const response = await apiRequest<User>(getApiConfig(), "/v1/users/invalid");

if (response.error) {
switch (response.status) {
case 400:
console.error("Bad request:", response.error);
break;
case 401:
console.error("Unauthorized");
break;
case 404:
console.error("User not found");
break;
case 500:
console.error("Server error:", response.error);
break;
}
}

Client Info & Audit Logging

The REST client also supports client info extraction for audit logging:

import { getApiConfig, apiRequest, extractClientInfo } from "@/lib/api";
import { NextRequest } from "next/server";

export async function POST(request: NextRequest) {
const clientInfo = extractClientInfo(request);

const response = await apiRequest<Result>(getApiConfig(), "/v1/auth/login", {
method: "POST",
body: { email, password },
...clientInfo, // Includes userAgent and clientIp
});
}

To tag the source service, pass sourceService in the options (the library does not read any SOURCE_SERVICE env var). See the GraphQL Client docs for details.

Pre-built Routes

The library includes pre-built route functions for common operations. Each takes the ApiClientConfig as its first argument:

import {
// User routes
getUserProfile,
getUserPermissions,
getUserAccounts,
checkUserExists,
// Session routes
getActiveSessions,
revokeSession,
revokeAllOtherSessions,
// Audit routes
getMyAuditLog,
reportAuditEvent,
} from "@elcto/api";
import { getApiConfig } from "@/lib/api";

// Get user profile (wrapped in ApiResponse — use .data)
const profile = await getUserProfile(getApiConfig(), "user-123");
console.log(profile.data?.name);

// Get user permissions (wrapped in ApiResponse — use .data)
const permissions = await getUserPermissions(getApiConfig(), "user-123");
console.log(permissions.data?.is_super_admin);

// Get active sessions (second arg is the current session token, not a userId)
const { sessions } = await getActiveSessions(getApiConfig(), currentToken);

// Get activity log
const auditPage = await getMyAuditLog(getApiConfig(), { page: 1, limit: 20 });

See the Pre-built Routes documentation for complete reference.