@volverjs/data
Version:
Repository pattern implementation with a tiny HttpClient based on Fetch API.
544 lines (543 loc) • 21.2 kB
TypeScript
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 {};