feat(api): add api communication helpers

This commit is contained in:
Julien Oculi 2024-06-13 12:22:49 +02:00
parent 756c5564b3
commit f2348b0177
2 changed files with 73 additions and 1 deletions

View file

@ -18,6 +18,9 @@
"*.tsx": "${capture}.*"
},
"cSpell.words": [
"magiclink",
"RPID",
"simplewebauthn",
"startserviceworker",
"technoshop",
"Technoshop",
@ -25,7 +28,7 @@
],
"cssvar.enable": true,
"cssvar.files": ["./_fresh/*"],
"conventionalCommits.scopes": ["css", "config", "ui", "pwa"],
"conventionalCommits.scopes": ["css", "config", "ui", "pwa", "api"],
"[ignore]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
}

69
src/utils.ts Normal file
View file

@ -0,0 +1,69 @@
import { JsonValue } from '$std/json/common.ts'
export type JsonCompatible = JsonValue | { toJSON(): JsonValue } | unknown
export function respondApi<
Kind extends ApiPayload['kind'],
Payload extends JsonCompatible,
>(kind: Kind, payload?: Payload, status?: number, statusText?: string): Response {
if (kind === 'error') {
return Response.json({
kind: 'error',
error: String(payload ?? ''),
} as ApiPayload, {
status: status ?? 500,
statusText
})
}
return Response.json({
kind: 'success',
data: payload ?? null,
} as ApiPayload)
}
export async function requestApi<
Payload extends JsonCompatible | undefined,
ApiResponse extends JsonCompatible,
>(
route: string,
method: 'GET' | 'POST' | 'DELETE' | 'PATCH',
payload?: Payload | null,
): Promise<ApiResponse> {
const csrf = getCookie('_CSRF') ?? ''
const base = new URL('/api/', location.origin)
const endpoint = new URL(route.startsWith('/') ? `.${route}` : route, base.href)
const response = await fetch(endpoint, {
method,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-CSRF-TOKEN': csrf
},
body: payload ? JSON.stringify(payload) : null,
})
const apiPayload = await response.json() as ApiPayload<ApiResponse>
if (apiPayload.kind === 'error') {
throw new Error(`api request error while getting "${endpoint.href}"`, {
cause: apiPayload.error,
})
}
return apiPayload.data
}
export type ApiPayload<ApiResponse extends JsonCompatible = never> = {
kind: 'success'
data: ApiResponse
} | {
kind: 'error'
error: string
}
function getCookie(name: string): string | undefined {
const cookiesEntries = document.cookie.split(';').map(cookie => cookie.trim().split('='))
const cookies = Object.fromEntries(cookiesEntries)
return cookies[name]
}