@spotable/attio-sdk
Version:
Client for Attio REST API
135 lines (116 loc) • 3.67 kB
text/typescript
import fetch, { Response } from "node-fetch";
import ora from "ora";
import logger from "./logger";
export interface AttioObject {
id: {
workspace_id: string;
object_id: string;
};
api_slug: string;
singular_noun: string;
plural_noun: string;
created_at: string;
updated_at?: string;
}
export interface AttioAttribute {
id: {
workspace_id: string;
object_id: string;
attribute_id: string;
};
title: string;
description: string | null;
api_slug: string;
type: string;
is_system_attribute: boolean;
is_writable: boolean;
is_required: boolean;
is_unique: boolean;
is_multiselect: boolean;
is_default_value_enabled: boolean;
is_archived: boolean;
default_value: any;
relationship: any;
config: Record<string, any>;
created_at: string;
}
class HTTPResponseError extends Error {
constructor(public response: Response) {
super(`HTTP Error Response: ${response.status} ${response.statusText}`);
this.response = response;
}
}
async function logError(error: unknown): Promise<void> {
if (error instanceof HTTPResponseError) {
const body = await error.response.json();
logger.error(`API error (${error.response.status}): ${JSON.stringify(body)}`);
} else {
logger.error(`Error fetching schema`, { error });
}
}
async function checkStatus<R>(response: Response): Promise<R> {
if (response.ok) {
return response.json() as R;
}
throw new HTTPResponseError(response);
}
async function fetchAttioObjects(apiKey: string): Promise<AttioObject[]> {
const fetchLoader = ora("Fetching Attio objects").start();
try {
const response = await fetch("https://api.attio.com/v2/objects", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
});
const body = await checkStatus<{ data: AttioObject[] }>(response);
if (!response.ok) {
logger.error(`Failed to fetch objects: ${response.statusText}`, {
response: body,
});
throw new Error(`Failed to fetch objects: ${response.statusText}`);
}
const objects = body.data;
fetchLoader.succeed(`Found ${objects.length} objects`);
return objects;
} catch (error) {
fetchLoader.fail("Failed to fetch Attio objects");
await logError(error);
throw error;
}
}
async function fetchAttioAttributes(apiKey: string, object: AttioObject): Promise<AttioAttribute[]> {
const fetchLoader = ora(`Fetching attributes for ${object.singular_noun}`).start();
try {
const response = await fetch(`https://api.attio.com/v2/objects/${object.api_slug}/attributes`, {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
});
const body = await checkStatus<{ data: AttioAttribute[] }>(response);
const attributes = body.data;
fetchLoader.succeed(`Found ${attributes.length} attributes for ${object.singular_noun}`);
return attributes;
} catch (error) {
fetchLoader.fail(`Failed to fetch attributes for ${object.singular_noun}`);
await logError(error);
throw error;
}
}
export async function fetchAttioSchema(apiKey: string) {
const fetchLoader = ora("Fetching Attio schema").start();
const objects = await fetchAttioObjects(apiKey);
const attributes: Record<string, AttioAttribute[]> = {};
for (const object of objects) {
const objectAttributes = await fetchAttioAttributes(apiKey, object);
attributes[object.api_slug] = objectAttributes;
}
fetchLoader.succeed("Attio schema fetched successfully");
return {
objects,
attributes,
};
}