From aa27ac1142bc60041095d506fb9487d7bfe62989 Mon Sep 17 00:00:00 2001 From: EugeneTes Date: Sat, 15 Aug 2026 11:55:09 +0000 Subject: [PATCH] Add authenticated fetch wrapper for the todos API --- frontend/src/lib/api.ts | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 frontend/src/lib/api.ts diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts new file mode 100644 index 0000000..9d82a8b --- /dev/null +++ b/frontend/src/lib/api.ts @@ -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 { + 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 { + 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 { + const res = await assertOk(await authedFetch('/api/todos')); + return res.json(); + }, + async create(title: string): Promise { + const res = await assertOk( + await authedFetch('/api/todos', { method: 'POST', body: JSON.stringify({ title }) }) + ); + return res.json(); + }, + async setCompleted(id: number, completed: boolean): Promise { + const res = await assertOk( + await authedFetch(`/api/todos/${id}`, { + method: 'PATCH', + body: JSON.stringify({ completed }) + }) + ); + return res.json(); + }, + async remove(id: number): Promise { + await assertOk(await authedFetch(`/api/todos/${id}`, { method: 'DELETE' })); + } +};