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
![Data fetching in '/apps/[appName]' route in open source ACI.dev platform.](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afit%3A875%2F1%2AUtTlg_Wxt8dLRXuuAgVHUQ.png)
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<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