Data fetching in '/apps/[appName]' route in open source ACI.dev platform.

In this article, we are going to review API layer in /apps/GITHUB route in ACI.dev platform. We will look at: Locating the /apps/GITHUB route apps/GITHUB folder API Layer in apps/GITHUB/page.tsx This /apps/GITHUB route loads a page that looks like below: ACI.dev is the open source platform that connects your AI agents to 600+ tool integrations with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server. Locating the /apps/GITHUB route ACI.dev is open source, you can find their code at aipotheosis-labs/aci. This codebase has the below project structure: apps backend frontend frontend ACI.dev is built using Next.js, I usually confirm this by looking for next.config.ts at the root of the frontend folder. And there is a src folder and app folder inside this src folder. This means this project is built using app router. From here on, it makes it super easy to locate /apps/GITHUB route since this is going to be a folder, according to how app router works in Next.js You will find the apps/[appName] folder in the above image. [appName] here indicates that this is dynamic route. There won’t be any GITHUB folder, instead this is a param accessible in apps/[appName]/page.tsx apps/[appName] folder apps folder has the below structure: page.tsx- file It contains only 1 file, page.tsx. API layer in apps/[appName] This below code is picked from aci.dev/frontend/…/apps/[appName]/page.tsx. useEffect(() => { async function loadData() { try { const apiKey = getApiKey(activeProject); const app = await getApp(appName, apiKey); setApp(app); const functions = await getFunctionsForApp(appName, apiKey); setFunctions(functions); const appConfig = await getAppConfig(appName, apiKey); setAppConfig(appConfig); } catch (error) { console.error("Error fetching app data:", error); } } loadData(); }, [appName, activeProject]); getApiKey: This below code is imported from /lib/util.ts import { Project } from "@/lib/types/project"; export function getApiKey(project: Project, agentId?: string): string { if ( !project || !project.agents || project.agents.length === 0 || !project.agents[0].api_keys || project.agents[0].api_keys.length === 0 ) { throw new Error( `No API key available in project: ${project.id} ${project.name}`, ); } if (agentId) { const agent = project.agents.find((agent) => agent.id === agentId); if (!agent) { throw new Error(`Agent ${agentId} not found in project ${project.id}`); } return agent.api_keys[0].key; } return project.agents[0].api_keys[0].key; } getApp getApp is defined as shown below: export async function getApp( appName: string, apiKey: string, ): Promise { const apps = await getApps([appName], apiKey); return apps.length > 0 ? apps[0] : null; } getFunctionsForApp export async function getFunctionsForApp( appName: string, apiKey: string, ): Promise { const params = new URLSearchParams(); params.append("app_names", appName); const response = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/v1/functions?${params.toString()}`, { method: "GET", headers: { "X-API-KEY": apiKey, }, }, ); if (!response.ok) { throw new Error( `Failed to fetch functions: ${response.status} ${response.statusText}`, ); } const functions = await response.json(); return functions; } This above code is picked from frontend/lib/api/appFunction.ts. About me: Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos. Configure features such as Changesets, Supabase authentication in your Next.js project using Think Throo CLI. Business enquiries — ramu@thinkthroo.com My Github — https://github.com/ramu-narasinga My website — https://ramunarasinga.com My YouTube channel — https://www.youtube.com/@ramu-narasinga Learning platform — https://thinkthroo.com Codebase Architecture — https://app.thinkthroo.com/architecture Best practices — https://app.thinkthroo.com/best-practices Production-grade projects — https://app.thinkthroo.com/production-grade-projects References: https://platform.aci.dev/apps/GITHUB https://github.com/aipotheosis-labs/aci/blob/main/frontend/src/app/apps/%5BappName%5D/page.tsx https://github.com/aipotheosis-labs/aci/blob/main/frontend/src/lib/api/app.ts#L48

May 9, 2025 - 05:34
 0
Data fetching in '/apps/[appName]' route in open source ACI.dev platform.

In this article, we are going to review API layer in /apps/GITHUB route in ACI.dev platform. We will look at:

  1. Locating the /apps/GITHUB route

  2. apps/GITHUB folder

  3. API Layer in apps/GITHUB/page.tsx

This /apps/GITHUB route loads a page that looks like below:

ACI.dev is the open source platform that connects your AI agents to 600+ tool integrations with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server.

Locating the /apps/GITHUB route

ACI.dev is open source, you can find their code at aipotheosis-labs/aci. This codebase has the below project structure:

  1. apps

  2. backend

  3. frontend

frontend

ACI.dev is built using Next.js, I usually confirm this by looking for next.config.ts at the root of the frontend folder.

And there is a src folder and app folder inside this src folder. This means this project is built using app router.

From here on, it makes it super easy to locate /apps/GITHUB route since this is going to be a folder, according to how app router works in Next.js

You will find the apps/[appName] folder in the above image. [appName] here indicates that this is dynamic route. There won’t be any GITHUB folder, instead this is a param accessible in apps/[appName]/page.tsx

apps/[appName] folder

apps folder has the below structure:

  1. page.tsx- file

It contains only 1 file, page.tsx.

API layer in apps/[appName]

This below code is picked from aci.dev/frontend/…/apps/[appName]/page.tsx.

useEffect(() => {
  async function loadData() {
    try {
      const apiKey = getApiKey(activeProject);

      const app = await getApp(appName, apiKey);
      setApp(app);

      const functions = await getFunctionsForApp(appName, apiKey);
      setFunctions(functions);

      const appConfig = await getAppConfig(appName, apiKey);
      setAppConfig(appConfig);
    } catch (error) {
      console.error("Error fetching app data:", error);
    }
  }

  loadData();
}, [appName, activeProject]);

getApiKey:

This below code is imported from /lib/util.ts

import { Project } from "@/lib/types/project";

export function getApiKey(project: Project, agentId?: string): string {
  if (
    !project ||
    !project.agents ||
    project.agents.length === 0 ||
    !project.agents[0].api_keys ||
    project.agents[0].api_keys.length === 0
  ) {
    throw new Error(
      `No API key available in project: ${project.id} ${project.name}`,
    );
  }
  if (agentId) {
    const agent = project.agents.find((agent) => agent.id === agentId);
    if (!agent) {
      throw new Error(`Agent ${agentId} not found in project ${project.id}`);
    }
    return agent.api_keys[0].key;
  }
  return project.agents[0].api_keys[0].key;
}

getApp

getApp is defined as shown below:

export async function getApp(
  appName: string,
  apiKey: string,
): Promise<App | null> {
  const apps = await getApps([appName], apiKey);
  return apps.length > 0 ? apps[0] : null;
}

getFunctionsForApp

export async function getFunctionsForApp(
  appName: string,
  apiKey: string,
): Promise<AppFunction[]> {
  const params = new URLSearchParams();
  params.append("app_names", appName);

  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_URL}/v1/functions?${params.toString()}`,
    {
      method: "GET",
      headers: {
        "X-API-KEY": apiKey,
      },
    },
  );

  if (!response.ok) {
    throw new Error(
      `Failed to fetch functions: ${response.status} ${response.statusText}`,
    );
  }

  const functions = await response.json();
  return functions;
}

This above code is picked from frontend/lib/api/appFunction.ts.

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

Configure features such as Changesets, Supabase authentication in your Next.js project using Think Throo CLI.

Business enquiries — ramu@thinkthroo.com

My Github — https://github.com/ramu-narasinga

My website — https://ramunarasinga.com

My YouTube channel — https://www.youtube.com/@ramu-narasinga

Learning platform — https://thinkthroo.com

Codebase Architecture — https://app.thinkthroo.com/architecture

Best practices — https://app.thinkthroo.com/best-practices

Production-grade projects — https://app.thinkthroo.com/production-grade-projects

References:

  1. https://platform.aci.dev/apps/GITHUB

  2. https://github.com/aipotheosis-labs/aci/blob/main/frontend/src/app/apps/%5BappName%5D/page.tsx

  3. https://github.com/aipotheosis-labs/aci/blob/main/frontend/src/lib/api/app.ts#L48