feat(api): ✨ add api communication helpers
This commit is contained in:
parent
756c5564b3
commit
f2348b0177
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -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
69
src/utils.ts
Normal 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]
|
||||
}
|
Loading…
Reference in a new issue