API Client
This page documents the API client layer in frontend/src/api/.
client.ts - API Functions
- Location:
src/api/client.ts
Provides typed functions for all API endpoints using Axios.
Setup
import axios from 'axios'
const api = axios.create({
baseURL: '/api',
headers: {
'Content-Type': 'application/json',
},
})
The base URL /api works with both:
Development: Vite proxies requests to the backend
Production: Same origin, backend serves the frontend
API Objects
runsApi
export const runsApi = {
// List all runs with optional filtering
list: async (params?: { status?: string; limit?: number; offset?: number }) => {
const { data } = await api.get<RunListResponse>('/runs', { params })
return data
},
// Get a specific run by ID
get: async (runId: string) => {
const { data } = await api.get<Run>(`/runs/${runId}`)
return data
},
// Create a new run
create: async (run: RunCreate) => {
const { data } = await api.post<Run>('/runs', run)
return data
},
// Cancel or delete a run
cancel: async (runId: string) => {
const { data } = await api.delete<Run>(`/runs/${runId}`)
return data
},
// Get the SSE URL for log streaming
getLogsUrl: (runId: string, fromStart = true) => {
return `/api/runs/${runId}/logs?from_start=${fromStart}`
},
}
configsApi
export const configsApi = {
// List available configuration templates
listTemplates: async () => {
const { data } = await api.get<TemplateListResponse>('/configs/templates')
return data
},
// Get content of a specific template
getTemplate: async (name: string) => {
const { data } = await api.get<TemplateContent>(`/configs/templates/${name}`)
return data
},
}
artifactsApi
export const artifactsApi = {
// List artifacts for a run
list: async (runId: string, path = '') => {
const { data } = await api.get<ArtifactListResponse>(`/runs/${runId}/artifacts`, {
params: path ? { path } : undefined,
})
return data
},
// Get download URL for an artifact
getDownloadUrl: (runId: string, filePath: string) => {
return `/api/runs/${runId}/artifacts/${filePath}`
},
}
topologyApi
export const topologyApi = {
// List available topologies
list: async () => {
const { data } = await api.get<TopologyListResponse>('/topology')
return data
},
// Get topology data with node positions
get: async (name: string) => {
const { data } = await api.get<TopologyResponse>(`/topology/${name}`)
return data
},
}
codebaseApi
export const codebaseApi = {
// Get directory tree
getTree: async () => {
const { data } = await api.get<ModuleTreeResponse>('/codebase/tree')
return data
},
// Get file content
getFile: async (path: string) => {
const { data } = await api.get<FileContent>(`/codebase/file/${path}`)
return data
},
// Search files by name
search: async (query: string, limit = 20) => {
const { data } = await api.get<SearchResult[]>('/codebase/search', {
params: { q: query, limit },
})
return data
},
}
systemApi
export const systemApi = {
// Health check
health: async () => {
const { data } = await api.get<HealthResponse>('/health')
return data
},
}
types.ts - TypeScript Interfaces
- Location:
src/api/types.ts
Defines TypeScript interfaces for all API request/response types.
Run Types
// Run status values
export type RunStatus = 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED'
// Progress information for running simulations
export interface RunProgress {
current_erlang: number | null
total_erlangs: number | null
current_iteration: number | null
total_iterations: number | null
percent_complete: number | null
}
// Full run object
export interface Run {
id: string
name: string | null
status: RunStatus
template: string
created_at: string
started_at: string | null
completed_at: string | null
error_message: string | null
progress: RunProgress | null
}
// Request body for creating a run
export interface RunCreate {
run_id?: string // Optional custom ID
name?: string // Optional display name
template: string // Template filename
config_content?: string // Optional INI content override
}
// Paginated run list response
export interface RunListResponse {
runs: Run[]
total: number
limit: number
offset: number
}
Config Types
export interface Template {
name: string
path: string
description: string
}
export interface TemplateListResponse {
templates: Template[]
}
export interface TemplateContent {
name: string
content: string
}
Topology Types
export interface TopologyNode {
id: number
label: string
x: number
y: number
}
export interface TopologyLink {
source: number
target: number
weight: number
}
export interface TopologyResponse {
name: string
nodes: TopologyNode[]
links: TopologyLink[]
metadata: {
num_nodes: number
num_links: number
}
}
export interface TopologyListResponse {
topologies: string[]
}
Artifact Types
export interface Artifact {
name: string
path: string
type: 'file' | 'directory'
size: number
modified: string
}
export interface ArtifactListResponse {
items: Artifact[]
path: string
}
Codebase Types
export interface FileTreeNode {
name: string
type: 'file' | 'directory'
path: string
children?: FileTreeNode[]
}
export interface ModuleTreeResponse {
tree: FileTreeNode
}
export interface FileContent {
path: string
content: string
language: string
size: number
}
export interface SearchResult {
path: string
type: 'file' | 'directory'
}
System Types
export interface HealthResponse {
status: 'healthy' | 'unhealthy'
version: string
database: 'connected' | 'disconnected'
}
Usage with React Query
The API client functions are designed to work seamlessly with React Query.
Basic Query
import { useQuery } from '@tanstack/react-query'
import { runsApi } from '@/api/client'
function MyComponent() {
const { data, isLoading, error } = useQuery({
queryKey: ['runs'],
queryFn: runsApi.list,
})
if (isLoading) return <Spinner />
if (error) return <Error message={error.message} />
return <RunList runs={data.runs} />
}
Query with Parameters
const { data } = useQuery({
queryKey: ['runs', { status: 'RUNNING' }],
queryFn: () => runsApi.list({ status: 'RUNNING' }),
})
Dependent Query
const { data: run } = useQuery({
queryKey: ['run', runId],
queryFn: () => runsApi.get(runId),
enabled: !!runId, // Only run when runId is truthy
})
Mutation
import { useMutation, useQueryClient } from '@tanstack/react-query'
function CreateRunButton() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: runsApi.create,
onSuccess: () => {
// Invalidate runs list to refetch
queryClient.invalidateQueries({ queryKey: ['runs'] })
},
})
return (
<button
onClick={() => mutation.mutate({ template: 'minimal.ini' })}
disabled={mutation.isLoading}
>
{mutation.isLoading ? 'Creating...' : 'Create Run'}
</button>
)
}
Polling
const { data } = useQuery({
queryKey: ['runs'],
queryFn: runsApi.list,
refetchInterval: 5000, // Refetch every 5 seconds
})