@volverjs/data
Version:
Repository pattern implementation with a tiny HttpClient based on Fetch API.
268 lines (267 loc) • 9.6 kB
TypeScript
import type { HttpClientInstance, HttpClientRequestOptions, HttpClientUrlTemplate } from './HttpClient';
import type { Repository } from './Repository';
import type { ParamMap } from './types';
type RepositoryHttpReadPendingRequest<Type> = {
responsePromise: Promise<{
ok: boolean;
aborted?: boolean;
abortReason?: string;
data?: Type[];
item?: Type;
metadata?: ParamMap;
}>;
abort: (reason?: string) => void;
signal: AbortSignal;
count: number;
};
export type RepositoryHttpReadOptions = HttpClientRequestOptions & {
key?: string | number | boolean;
};
export type RepositoryHttpOptions<Type, TResponse = unknown> = {
/**
* The httpClient instance scope (name)
* @default undefined
* @example
* ```typescript
* addHttpClient('v2', { prefixUrl: 'https://myapi.com/v2' })
* const { read } = useRepositoryHttp<{ id: string }>('users/?:id', { httpClientScope: 'v2' })
* read({ id: 1 })
* //=> GET https://myapi.com/v2/?id=1
* ```
*/
httpClientScope?: string;
/**
* The prefix url to use for all requests.
* @default undefined
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/?:id', { httpClientOptions: { prefixUrl: 'https://example.com' } })
* repository.read({ id: 1 })
* //=> GET https://example.com/?id=1
* ```
*/
httpClientOptions?: HttpClientRequestOptions;
/**
* A function to transform the raw response data into the expected data type.
* @remarks
* Must return an array of items.
* @default
* `(raw: unknown) => Array.isArray(raw) ? raw : ([raw] as Type[])`
* @example
* ```typescript
* const responseAdapter = (raw) => [new Type(raw)]
* const repository = new RepositoryHttp(client, 'users/?:id', { responseAdapter })
* ```
*/
responseAdapter?: (raw: TResponse) => Type[];
/**
* A function to transform the request data into the expected data type.
* @default
* `(item: Type): unknown => item`
* @example
* ```typescript
* const requestAdapter = (item) => ({ ...item, foo: 'bar' })
* const repository = new RepositoryHttp(client, 'users/?:id', { requestAdapter })
* ```
*/
requestAdapter?: (item: Type) => unknown;
/**
* A function to extract metadata from the response.
* @default
* `(response: Response): ParamMap | undefined => {
* let toReturn = undefined
* if (response.headers.has('Content-Language')) {
* toReturn = {
* contentLanguage: response.headers.get('Content-Language'),
* }
* }
* if (response.headers.has('Accept-Language')) {
* toReturn = {
* acceptLanguage: response.headers.get('Accept-Language'),
* }
* }
* if (response.headers.has('X-Total-Count')) {
* toReturn = {
* ...toReturn,
* total: response.headers.get('X-Total-Count'),
* }
* }
* return toReturn
* }`
* @example
* ```typescript
* const metadataAdapter = (response) => {
* if (response.headers.has('X-Pagination')) {
* return JSON.parse(response.headers.get('X-Pagination'))
* }
* return undefined
* }
* const repository = new RepositoryHttp(client, 'users/?:id', { metadataAdapter })
* ```
*/
metadataAdapter?: (response: Response) => ParamMap;
/**
* A function to generate a key for the request.
* @default
* `(str: string) => Hash.cyrb53(str)`
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/?:id', { hashFunction: Hash.djb2 })
* ```
*/
hashFunction?: (str: string) => number;
/**
* The class to apply to the items. An alternative to `responseAdapter`.
* @default undefined
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/?:id', { class: Type })
* ```
*/
class?: new (...args: any[]) => Type;
};
export declare class RepositoryHttp<Type, TResponse = unknown> implements Repository<Type> {
private _client;
private _template;
private _responseAdapter;
private _requestAdapter;
private _metadataAdapter;
private _hashFunction;
private _readPendingRequests;
private _httpClientOptions?;
/**
* @param client The HTTP client to use.
* @param template The URL template to use for requests.
* @param options The options to use.
*/
constructor(client: HttpClientInstance, template: string | HttpClientUrlTemplate, options?: RepositoryHttpOptions<Type, TResponse>);
/**
* @params params - The parameters to use in the request template URL or query.
* @params options - The HTTP Client request options.
* @returns A an object with the response promise and a function to abort the request.
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/:type')
* const { response, abort } = repository.read({ type: 'admin', page: 1 })
* const { data, item, metadata, ok } = await response
* //=> GET /users/admin?page=1
* ```
*/
read: (params?: ParamMap, options?: RepositoryHttpReadOptions) => Omit<RepositoryHttpReadPendingRequest<Type>, "count"> | {
abort: (reason?: string) => void;
responsePromise: Promise<{
data: Type[];
item: Type;
metadata: ParamMap | undefined;
ok: boolean;
aborted?: undefined;
abortReason?: undefined;
} | {
ok: boolean;
aborted: boolean;
abortReason: any;
data?: undefined;
item?: undefined;
metadata?: undefined;
}>;
signal: AbortSignal;
};
/**
* @params payload - The payload to use in the request body.
* @params params - The parameters to use in the request template URL or query.
* @params options - The HTTP Client request options.
* @returns A an object with the response promise and a function to abort the request.
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/:type')
* const payload = { name: 'John' }
* const { response, abort } = repository.create(payload, { type: 'admin' })
* const { data, item, metadata, ok } = await response
* //=> POST /users/admin
* ```
*/
create: (payload?: Type | Type[], params?: ParamMap, options?: HttpClientRequestOptions) => {
abort: (reason?: string) => void;
responsePromise: Promise<{
data: Type[];
item: Type;
metadata: ParamMap | undefined;
ok: boolean;
aborted?: undefined;
abortReason?: undefined;
} | {
ok: boolean;
aborted: boolean;
abortReason: any;
data?: undefined;
item?: undefined;
metadata?: undefined;
}>;
signal: AbortSignal;
};
/**
* @params payload - The payload to use in the request body.
* @params params - The parameters to use in the request template URL or query.
* @params options - The HTTP Client request options.
* @returns A an object with the response promise and a function to abort the request.
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/:type/?:id')
* const payload = { id: 1, name: 'John' }
* const { response, abort } = repository.update(payload, { type: 'admin', id: 1 })
* const { data, item, metadata, ok } = await response
* //=> PUT /users/admin/1
* ```
*/
update: (payload?: Type | Type[], params?: ParamMap, options?: HttpClientRequestOptions) => {
abort: (reason?: string) => void;
responsePromise: Promise<{
data: Type[];
item: Type;
metadata: ParamMap | undefined;
ok: boolean;
aborted?: undefined;
abortReason?: undefined;
} | {
ok: boolean;
aborted: boolean;
abortReason: any;
data?: undefined;
item?: undefined;
metadata?: undefined;
}>;
signal: AbortSignal;
};
/**
* @params params - The parameters to use in the request template URL or query.
* @params options - The HTTP Client request options.
* @returns A an object with the response promise and a function to abort the request.
* @example
* ```typescript
* const repository = new RepositoryHttp(client, 'users/:type/?:id')
* const { response, abort } = repository.delete({ type: 'admin', id: 1 })
* const { ok } = await response
* //=> DELETE /users/admin/1
* ```
*/
remove: (params?: ParamMap, options?: HttpClientRequestOptions) => {
abort: (reason?: string) => void;
responsePromise: Promise<{
ok: boolean;
aborted?: undefined;
abortReason?: undefined;
} | {
ok: boolean;
aborted: boolean;
abortReason: any;
}>;
signal: AbortSignal;
};
private _hasRepositoryHttpReadPendingRequest;
private _deleteRepositoryHttpReadPendingRequest;
private _cloneRepositoryHttpReadPendingRequest;
private _setRepositoryHttpReadPendingRequest;
private _requestUrl;
private _requestOptions;
}
export {};