Files
aranroig.com/frontend/app/composables/useApi.ts
Aran Roig 770f302bc3
All checks were successful
Build and Deploy Nuxt / build (push) Successful in 2m26s
Cards!
2026-09-20 03:15:16 +02:00

63 lines
1.9 KiB
TypeScript

// composables/useApi.js
import { ref } from 'vue'
export const ADMIN_TOKEN_COOKIE = 'admin_token'
export class ApiError extends Error {
status: number
constructor(message: string, status: number) {
super(message)
this.status = status
}
}
function normalizeUrl(url: string): string {
return url.replace(/\/+$/, '')
}
export default function useApi() {
const config = useRuntimeConfig()
const baseUrl = `${normalizeUrl(config.public.apiBaseUrl)}/api`
// Generic GET request
const get = async (endpoint) => {
const res = await fetch(`${baseUrl}${endpoint}`)
if (!res.ok) throw new ApiError(`API GET ${endpoint} failed`, res.status)
return res.json()
}
// Generic POST request
const post = async (endpoint, payload) => {
const res = await fetch(`${baseUrl}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
if (!res.ok) throw new ApiError(`API POST ${endpoint} failed`, res.status)
return res.json()
}
// Authenticated requests (JWT stored in cookie by useAuth)
const authHeaders = (): Record<string, string> => {
const token = useCookie<string | null>(ADMIN_TOKEN_COOKIE).value
return token ? { Authorization: `Bearer ${token}` } : {}
}
const getAuth = async (endpoint) => {
const res = await fetch(`${baseUrl}${endpoint}`, { headers: authHeaders() })
if (!res.ok) throw new ApiError(`API GET ${endpoint} failed`, res.status)
return res.json()
}
const postAuth = async (endpoint, payload) => {
const res = await fetch(`${baseUrl}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...authHeaders() },
body: JSON.stringify(payload)
})
if (!res.ok) throw new ApiError(`API POST ${endpoint} failed`, res.status)
return res.json()
}
return { get, post, getAuth, postAuth }
}