UNPKG

@volverjs/data

Version:

Repository pattern implementation with a tiny HttpClient based on Fetch API.

544 lines (543 loc) 21.2 kB
import type { ParamMap } from 'src/types'; import type { App, Ref } from 'vue'; import type { HttpClientInputTemplate, HttpClientInstanceOptions, HttpClientMethod, HttpClientRequestOptions, HttpClientResponse, HttpClientUrlTemplate, HTTPError } from '../HttpClient'; import type { RepositoryHttpOptions, RepositoryHttpReadOptions } from '../RepositoryHttp'; import { HttpClient } from '../HttpClient'; import { RepositoryHttp } from '../RepositoryHttp'; export declare enum HttpRequestStatus { loading = "loading", error = "error", success = "success", idle = "idle" } type HttpClientRequestOptionsWithImmediate = HttpClientRequestOptions & { immediate?: boolean; }; type HttpClientComposableRequestOptions = HttpClientRequestOptionsWithImmediate | Ref<HttpClientRequestOptionsWithImmediate>; type HttpClientComposableInputTemplate = HttpClientInputTemplate | Ref<HttpClientInputTemplate>; type RepositoryHttpReadOptionsWithImmediate = RepositoryHttpReadOptions & { immediate?: boolean; }; type RepositoryHttpComposableReadOptions = RepositoryHttpReadOptionsWithImmediate | Ref<RepositoryHttpReadOptionsWithImmediate>; declare class HttpClientPlugin extends HttpClient { private _scope; constructor(options: HttpClientInstanceOptions & { scope: string; }); get scope(): string; install(app: App, { globalName }?: { globalName?: string | undefined; }): void; } /** * Create a new instance of a HttpClientPlugin. * @param options - The options for the http client {@link HttpClientInstanceOptions HttpClientInstanceOptions & { scope: string }} * @param options.scope - The scope (name) of the HttpClient instance * @returns The instance of the HttpClientPlugin, see {@link HttpClientPlugin} * @example * ```typescript * import { createApp } from 'vue' * import { createHttpClient } from '@volverjs/data/vue' * import App from './App.vue' * * const app = createApp(App) * const client = createHttpClient({ * prefixUrl: 'https://my.api.com' * }) * app.use(client) * ``` * * Multiple instances with `scope` * ```typescript * import { createApp } from 'vue' * import { createHttpClient } from '@volverjs/data/vue' * import App from './App.vue' * * const app = createApp(App) * const client = createHttpClient({ * prefixUrl: 'https://my.api-v2.com', * scope: 'apiV2' * }) * * app.use(client, { globalName: 'httpClientV2' }) * * const { requestPost } = useHttpClient('apiV2') * const { isLoading, isError, error, execute } = requestPost<User>( * 'user', * computed(() => ({ immediate: false, json: data.value })), * ) * ``` */ export declare function createHttpClient({ scope, ...options }?: HttpClientInstanceOptions & { scope?: string; }): HttpClientPlugin; /** * Use the composition API to remove an existing HttpClient instance (remove of http global instance is not permitted) * @param scope - The scope (name) of the HttpClient instance to remove * @returns - Boolean success or not */ export declare function removeHttpClient(scope: string): boolean; /** * Use the composition API to get the HttpClient instance and reactive methods. * @remarks * If `HttpClientPlugin` is not created with `createHttpClient` and installed first, `useHttpClient` throw the error "HttpClient instance not found". * @param scope - The scope (name) of the HttpClient instance * @example * ```html * <template> * <div> * <button @click="execute()">Execute</button> * <div v-if="isLoading">Loading...</div> * <div v-if="isError">{{ error }}</div> * <div v-if="data">{{ data.name }}</div> * </div> * </template> * * <script lang="ts" setup> * import { ref, computed } from 'vue' * import { useHttpClient } from '@volverjs/data/vue' * * const { client } = useHttpClient() * const isLoading = ref(false) * const isError = computed(() => error.value !== undefined) * const error = ref() * const data = ref<User>() * * type User = { * id: number, * name: string * } * * const execute = async () => { * isLoading.value = true * try { * const response = await client.get('user/1') * data.value = await response.json<User>() * } catch (e) { * error.value = e.message * } finally { * isLoading.value = false * } * } * </script> * ``` * @example * ```html * <template> * <div> * <button @click="execute()">Execute</button> * <div v-if="isLoading">Loading...</div> * <div v-if="isError">{{ error }}</div> * <div v-if="data">{{ data.name }}</div> * </div> * </template> * * <script setup> * import { useHttpClient } from '@volverjs/data/vue' * * type User = { * id: number, * name: string * } * * const { requestGet } = useHttpClient() * const { * isLoading, * isError, * error, * data, * execute, * } = requestGet<User>('user/1', { immediate: false }) * </script> * ``` * @example * ```html * <template> * <form @submit.prevent="execute()"> * <div v-if="isLoading">Loading...</div> * <div v-if="isError">{{ error }}</div> * <input type="text" v-model="data.name" /> * <button type="submit">Submit</button> * </form> * </template> * * <script lang="ts" setup> * import { useHttpClient } from '@volverjs/data/vue' * * type User = { * id: number * name: string * } * * const data = ref<Partial<User>>({ name: '' }) * * const { requestPost } = useHttpClient() * const { isLoading, isSuccess, isError, error, execute } = requestPost<User>( * 'user', * computed(() => ({ immediate: false, json: data.value })), * ) * </script> * ``` */ export declare function useHttpClient(scope?: string): { client: HttpClient; request: <T = unknown>(method: HttpClientMethod, url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; requestGet: <T>(url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; requestPost: <T>(url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; requestPut: <T>(url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; requestDelete: <T>(url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; requestHead: <T>(url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; requestPatch: <T>(url: HttpClientComposableInputTemplate, options?: HttpClientComposableRequestOptions) => { responsePromise?: import("ky").ResponsePromise<unknown> | undefined; abort?: ((reason?: string) => void) | undefined; signal?: AbortSignal | undefined; execute: (newUrl?: HttpClientInputTemplate, newOptions?: HttpClientRequestOptions) => { responsePromise: import("ky").ResponsePromise<unknown>; abort: (reason?: string) => void; signal: AbortSignal; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T | undefined, T | undefined>; response: Ref<HttpClientResponse | undefined, HttpClientResponse | undefined>; }; }; /** * Use the composition API to get a new instance of a RepositoryHttp. * @remarks * If `HttpClientPlugin` is not created with `createHttpClient` and installed first, `useRepositoryHttp` throw the error "HttpClient instance not found". * @param template - The template string for the repository * @param options - The options for the repository {@link RepositoryHttpOptions} * @returns The instance of the RepositoryHttp, see {@link RepositoryHttp} * @example * ```html * <template> * <div> * <button @click="execute">Execute</button> * <div v-if="isLoading">Loading...</div> * <div v-if="isError">{{ error }}</div> * <div v-if="data?.[0]">{{ data?.[0].name }}</div> * </div> * </template> * * <script lang="ts" setup> * import { ref, computed } from 'vue' * import { useRepositoryHttp, type HTTPError } from '@volverjs/data/vue' * * type User = { * id: number, * name: string * } * * const { repository } = useRepositoryHttp<User>('users/:id') * const isLoading = ref(false) * const isError = computed(() => error.value !== undefined) * const error = ref<HTTPError>() * const item = ref<User>() * * const execute = async () => { * isLoading.value = true * try { * const { request } = repository.read({ id: 1 }) * const response = await request * item.value = response.item * } catch (e) { * error.value = e.message * } finally { * isLoading.value = false * } * } * </script> * ``` * @example * ```html * <template> * <div> * <button @click="execute">Execute</button> * <div v-if="isLoading">Loading...</div> * <div v-if="isError">{{ error }}</div> * <div v-if="item">{{ item.name }}</div> * </div> * </template> * * <script lang="ts" setup> * import { useRepositoryHttp } from '@volverjs/data/vue' * * type User = { * id: number, * name: string * } * * const { read } = useRepositoryHttp<User>('users/:id') * const { isLoading, isSuccess, isError, error, item, execute } = read( * { id: 1 }, * { immediate: false } * ) * </script> * ``` */ export declare function useRepositoryHttp<T = unknown, TResponse = unknown>(template: string | HttpClientUrlTemplate, options?: RepositoryHttpOptions<T, TResponse>): { repository: RepositoryHttp<T, TResponse>; read: (params: ParamMap | Ref<ParamMap>, options?: RepositoryHttpComposableReadOptions) => { abort?: ((reason?: string) => void) | ((reason?: string) => void) | undefined; responsePromise?: Promise<{ ok: boolean; aborted?: boolean; abortReason?: string; data?: T[] | undefined; item?: T | undefined; metadata?: ParamMap; }> | Promise<{ data: T[]; item: T; metadata: ParamMap | undefined; ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; data?: undefined; item?: undefined; metadata?: undefined; }> | undefined; execute: (newParams?: ParamMap, newOptions?: RepositoryHttpReadOptions) => { abort: ((reason?: string) => void) | ((reason?: string) => void); responsePromise: Promise<{ ok: boolean; aborted?: boolean; abortReason?: string; data?: T[] | undefined; item?: T | undefined; metadata?: ParamMap; }> | Promise<{ data: T[]; item: T; metadata: ParamMap | undefined; ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; data?: undefined; item?: undefined; metadata?: undefined; }>; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T[] | undefined, T[] | undefined>; item: Ref<T | undefined, T | undefined>; metadata: Ref<ParamMap | undefined, ParamMap | undefined>; }; create: (payload: T | Ref<T> | T[] | Ref<T[]> | undefined, params?: ParamMap, options?: HttpClientComposableRequestOptions) => { abort?: ((reason?: string) => void) | undefined; responsePromise?: Promise<{ data: T[]; item: T; metadata: ParamMap | undefined; ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; data?: undefined; item?: undefined; metadata?: undefined; }> | undefined; execute: (newPayload?: T | T[] | undefined, newParams?: ParamMap, newOptions?: RepositoryHttpReadOptions) => { abort: (reason?: string) => void; responsePromise: Promise<{ data: T[]; item: T; metadata: ParamMap | undefined; ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; data?: undefined; item?: undefined; metadata?: undefined; }>; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T[] | undefined, T[] | undefined>; metadata: Ref<ParamMap | undefined, ParamMap | undefined>; }; update: (payload: T | Ref<T> | T[] | Ref<T[]> | undefined, params?: ParamMap, options?: HttpClientComposableRequestOptions) => { abort?: ((reason?: string) => void) | undefined; responsePromise?: Promise<{ data: T[]; item: T; metadata: ParamMap | undefined; ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; data?: undefined; item?: undefined; metadata?: undefined; }> | undefined; execute: (newPayload?: T | T[] | undefined, newParams?: ParamMap, newOptions?: RepositoryHttpReadOptions) => { abort: (reason?: string) => void; responsePromise: Promise<{ data: T[]; item: T; metadata: ParamMap | undefined; ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; data?: undefined; item?: undefined; metadata?: undefined; }>; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; data: Ref<T[] | undefined, T[] | undefined>; metadata: Ref<ParamMap | undefined, ParamMap | undefined>; }; remove: (params: ParamMap | Ref<ParamMap>, options?: HttpClientComposableRequestOptions) => { abort?: ((reason?: string) => void) | undefined; responsePromise?: Promise<{ ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; }> | undefined; execute: (newParams?: ParamMap, newOptions?: RepositoryHttpReadOptions) => { abort: (reason?: string) => void; responsePromise: Promise<{ ok: boolean; aborted?: undefined; abortReason?: undefined; } | { ok: boolean; aborted: boolean; abortReason: any; }>; }; isLoading: import("vue").ComputedRef<boolean>; isSuccess: import("vue").ComputedRef<boolean>; isError: import("vue").ComputedRef<boolean>; error: Readonly<Ref<HTTPError<unknown> | undefined, HTTPError<unknown> | undefined>>; }; }; export {};