Multi-tenant factory inspection system (SpiFox, Enkid, Alpet): - FastAPI backend with JWT auth, PostgreSQL (asyncpg) - Next.js 16 frontend with App Router, SWR data fetching - Machines CRUD with equipment parts management - Part lifecycle tracking (hours/count/date) with counters - Partial unique index for soft-delete support - 24 pytest tests passing, E2E verified Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
74 lines
2.0 KiB
TypeScript
74 lines
2.0 KiB
TypeScript
import { getStoredToken } from './auth-context';
|
|
import { getTenantFromPath } from './tenant-context';
|
|
|
|
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
|
|
|
|
function getHeaders(): HeadersInit {
|
|
const token = getStoredToken();
|
|
return {
|
|
'Content-Type': 'application/json',
|
|
...(token ? { 'Authorization': `Bearer ${token}` } : {}),
|
|
};
|
|
}
|
|
|
|
export async function fetcher<T>(url: string): Promise<T> {
|
|
const res = await fetch(`${API_BASE_URL}${url}`, {
|
|
headers: getHeaders(),
|
|
});
|
|
if (!res.ok) {
|
|
throw new Error('API request failed');
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
export function getTenantUrl(path: string, tenantId?: string): string {
|
|
const tenant = tenantId || getTenantFromPath();
|
|
if (!tenant) {
|
|
throw new Error('Tenant ID not found');
|
|
}
|
|
return `/api/${tenant}${path}`;
|
|
}
|
|
|
|
export const api = {
|
|
get: <T>(url: string) => fetcher<T>(url),
|
|
|
|
post: async <T>(url: string, data: unknown): Promise<T> => {
|
|
const res = await fetch(`${API_BASE_URL}${url}`, {
|
|
method: 'POST',
|
|
headers: getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) throw new Error('API request failed');
|
|
return res.json();
|
|
},
|
|
|
|
put: async <T>(url: string, data: unknown): Promise<T> => {
|
|
const res = await fetch(`${API_BASE_URL}${url}`, {
|
|
method: 'PUT',
|
|
headers: getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) throw new Error('API request failed');
|
|
return res.json();
|
|
},
|
|
|
|
patch: async <T>(url: string, data: unknown): Promise<T> => {
|
|
const res = await fetch(`${API_BASE_URL}${url}`, {
|
|
method: 'PATCH',
|
|
headers: getHeaders(),
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (!res.ok) throw new Error('API request failed');
|
|
return res.json();
|
|
},
|
|
|
|
delete: async <T>(url: string): Promise<T> => {
|
|
const res = await fetch(`${API_BASE_URL}${url}`, {
|
|
method: 'DELETE',
|
|
headers: getHeaders(),
|
|
});
|
|
if (!res.ok) throw new Error('API request failed');
|
|
return res.json();
|
|
},
|
|
};
|