Rewrite from Go + vanilla JS to Python (FastAPI) + React (TypeScript)
- Backend: Python 3.12 with FastAPI, SQLAlchemy, boto3 - Frontend: React 18 with TypeScript, Vite build tooling - Updated Dockerfile for multi-stage Node + Python build - Updated CI pipeline for Python backend - Removed old Go code (cmd/, internal/, go.mod, go.sum) - Updated README with new tech stack documentation
This commit is contained in:
87
frontend/src/api.ts
Normal file
87
frontend/src/api.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Grove, Tree, Graft, Fruit, CultivateResponse } from './types';
|
||||
|
||||
const API_BASE = '/api/v1';
|
||||
|
||||
async function handleResponse<T>(response: Response): Promise<T> {
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ detail: 'Unknown error' }));
|
||||
throw new Error(error.detail || `HTTP ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
// Grove API
|
||||
export async function listGroves(): Promise<Grove[]> {
|
||||
const response = await fetch(`${API_BASE}/groves`);
|
||||
return handleResponse<Grove[]>(response);
|
||||
}
|
||||
|
||||
export async function createGrove(data: { name: string; description?: string; is_public?: boolean }): Promise<Grove> {
|
||||
const response = await fetch(`${API_BASE}/groves`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return handleResponse<Grove>(response);
|
||||
}
|
||||
|
||||
export async function getGrove(name: string): Promise<Grove> {
|
||||
const response = await fetch(`${API_BASE}/groves/${name}`);
|
||||
return handleResponse<Grove>(response);
|
||||
}
|
||||
|
||||
// Tree API
|
||||
export async function listTrees(groveName: string): Promise<Tree[]> {
|
||||
const response = await fetch(`${API_BASE}/grove/${groveName}/trees`);
|
||||
return handleResponse<Tree[]>(response);
|
||||
}
|
||||
|
||||
export async function createTree(groveName: string, data: { name: string; description?: string }): Promise<Tree> {
|
||||
const response = await fetch(`${API_BASE}/grove/${groveName}/trees`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return handleResponse<Tree>(response);
|
||||
}
|
||||
|
||||
// Graft API
|
||||
export async function listGrafts(groveName: string, treeName: string): Promise<Graft[]> {
|
||||
const response = await fetch(`${API_BASE}/grove/${groveName}/${treeName}/grafts`);
|
||||
return handleResponse<Graft[]>(response);
|
||||
}
|
||||
|
||||
export async function createGraft(groveName: string, treeName: string, data: { name: string; fruit_id: string }): Promise<Graft> {
|
||||
const response = await fetch(`${API_BASE}/grove/${groveName}/${treeName}/graft`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return handleResponse<Graft>(response);
|
||||
}
|
||||
|
||||
// Fruit API
|
||||
export async function getFruit(fruitId: string): Promise<Fruit> {
|
||||
const response = await fetch(`${API_BASE}/fruit/${fruitId}`);
|
||||
return handleResponse<Fruit>(response);
|
||||
}
|
||||
|
||||
// Upload
|
||||
export async function cultivate(groveName: string, treeName: string, file: File, tag?: string): Promise<CultivateResponse> {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
if (tag) {
|
||||
formData.append('tag', tag);
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE}/grove/${groveName}/${treeName}/cultivate`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
return handleResponse<CultivateResponse>(response);
|
||||
}
|
||||
|
||||
// Download URL
|
||||
export function getDownloadUrl(groveName: string, treeName: string, ref: string): string {
|
||||
return `${API_BASE}/grove/${groveName}/${treeName}/+/${ref}`;
|
||||
}
|
||||
Reference in New Issue
Block a user