Add authenticated fetch wrapper for the todos API

This commit is contained in:
EugeneTes
2026-08-15 11:55:09 +00:00
parent cbcba53943
commit aa27ac1142

56
frontend/src/lib/api.ts Normal file
View File

@@ -0,0 +1,56 @@
import { supabase } from './supabase';
const API_URL = import.meta.env.VITE_API_URL;
if (!API_URL) throw new Error('Missing VITE_API_URL');
export type Todo = {
id: number;
title: string;
completed: boolean;
createdAt: string;
};
async function authedFetch(path: string, init: RequestInit = {}): Promise<Response> {
const { data } = await supabase.auth.getSession();
const token = data.session?.access_token;
if (!token) throw new Error('Not signed in');
const headers = new Headers(init.headers);
headers.set('Authorization', `Bearer ${token}`);
if (init.body && !headers.has('Content-Type')) headers.set('Content-Type', 'application/json');
return fetch(`${API_URL}${path}`, { ...init, headers });
}
async function assertOk(res: Response): Promise<Response> {
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`API ${res.status}: ${text || res.statusText}`);
}
return res;
}
export const api = {
async list(): Promise<Todo[]> {
const res = await assertOk(await authedFetch('/api/todos'));
return res.json();
},
async create(title: string): Promise<Todo> {
const res = await assertOk(
await authedFetch('/api/todos', { method: 'POST', body: JSON.stringify({ title }) })
);
return res.json();
},
async setCompleted(id: number, completed: boolean): Promise<Todo> {
const res = await assertOk(
await authedFetch(`/api/todos/${id}`, {
method: 'PATCH',
body: JSON.stringify({ completed })
})
);
return res.json();
},
async remove(id: number): Promise<void> {
await assertOk(await authedFetch(`/api/todos/${id}`, { method: 'DELETE' }));
}
};