fix: try to get json data from error
This commit is contained in:
parent
00308d6718
commit
6249d0bde9
15 changed files with 10179 additions and 63 deletions
10046
package-lock.json
generated
10046
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "react-rest-request",
|
"name": "react-rest-request",
|
||||||
"version": "0.5.4",
|
"version": "0.5.5",
|
||||||
"description": "Minimalistic REST API client for React inspired by Apollo",
|
"description": "Minimalistic REST API client for React inspired by Apollo",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"main": "./target/index.js",
|
"main": "./target/index.js",
|
||||||
|
|
|
@ -105,7 +105,7 @@ export class Client {
|
||||||
error: err,
|
error: err,
|
||||||
canceled,
|
canceled,
|
||||||
} as ResponseWithError,
|
} as ResponseWithError,
|
||||||
{}
|
canceled ? {} : err.json()
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
11
target/client.d.ts
vendored
11
target/client.d.ts
vendored
|
@ -1,13 +1,13 @@
|
||||||
import { Method } from './endpoint';
|
import { Method } from './endpoint';
|
||||||
export declare type ClientConfig = {
|
export interface ClientConfig {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
};
|
}
|
||||||
declare type PrepareRequestProps = {
|
export interface PrepareRequestProps {
|
||||||
url: string;
|
url: string;
|
||||||
method: Method;
|
method: Method;
|
||||||
headers: Record<string, string>;
|
headers: Record<string, string>;
|
||||||
variables: Record<string, any> | FormData;
|
variables: Record<string, any> | FormData;
|
||||||
};
|
}
|
||||||
export declare type RequestProps<R> = PrepareRequestProps & {
|
export declare type RequestProps<R> = PrepareRequestProps & {
|
||||||
transformResponseData?: (data: unknown) => R;
|
transformResponseData?: (data: unknown) => R;
|
||||||
};
|
};
|
||||||
|
@ -19,11 +19,10 @@ export declare type ClientResponse<Data extends Record<string, any>> = ResponseW
|
||||||
data: Data;
|
data: Data;
|
||||||
}>;
|
}>;
|
||||||
export declare class Client {
|
export declare class Client {
|
||||||
private config;
|
private readonly config;
|
||||||
private controller;
|
private controller;
|
||||||
constructor(config: ClientConfig);
|
constructor(config: ClientConfig);
|
||||||
prepareRequest(props: PrepareRequestProps): Request;
|
prepareRequest(props: PrepareRequestProps): Request;
|
||||||
request<Data extends Record<string, any>>({ transformResponseData, ...restProps }: RequestProps<Data>): Promise<ClientResponse<Data>>;
|
request<Data extends Record<string, any>>({ transformResponseData, ...restProps }: RequestProps<Data>): Promise<ClientResponse<Data>>;
|
||||||
cancelRequest(): void;
|
cancelRequest(): void;
|
||||||
}
|
}
|
||||||
export {};
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class Client {
|
||||||
error: err,
|
error: err,
|
||||||
canceled,
|
canceled,
|
||||||
},
|
},
|
||||||
{}
|
canceled ? {} : err.json()
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.then(([res, data]) => {
|
.then(([res, data]) => {
|
||||||
|
|
1
target/client_hook.d.ts
vendored
Normal file
1
target/client_hook.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export declare function useClient(): import("./client").Client[];
|
5
target/client_hook.js
Normal file
5
target/client_hook.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { useRequestContext } from './request_context';
|
||||||
|
export function useClient() {
|
||||||
|
const { client } = useRequestContext();
|
||||||
|
return [client];
|
||||||
|
}
|
8
target/index.d.ts
vendored
8
target/index.d.ts
vendored
|
@ -1,7 +1,7 @@
|
||||||
export * from './endpoint';
|
export * from './endpoint';
|
||||||
export * from './client';
|
export * from './client';
|
||||||
export * from './client-hook';
|
export * from './client_hook';
|
||||||
export * from './lazy-request-hook';
|
export * from './lazy_request_hook';
|
||||||
export * from './request-hook';
|
export * from './request_hook';
|
||||||
export * from './request-context';
|
export * from './request_context';
|
||||||
export * from './reducer';
|
export * from './reducer';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export * from './endpoint';
|
export * from './endpoint';
|
||||||
export * from './client';
|
export * from './client';
|
||||||
export * from './client-hook';
|
export * from './client_hook';
|
||||||
export * from './lazy-request-hook';
|
export * from './lazy_request_hook';
|
||||||
export * from './request-hook';
|
export * from './request_hook';
|
||||||
export * from './request-context';
|
export * from './request_context';
|
||||||
export * from './reducer';
|
export * from './reducer';
|
||||||
|
|
20
target/lazy_request_hook.d.ts
vendored
Normal file
20
target/lazy_request_hook.d.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { AnyEndpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint';
|
||||||
|
import { PublicRequestState } from './reducer';
|
||||||
|
import { ClientResponse } from './client';
|
||||||
|
export declare type LazyRequestConfig<R, V, P> = Readonly<{
|
||||||
|
variables?: V;
|
||||||
|
params?: P;
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
onComplete?: (data: R) => unknown;
|
||||||
|
onFailure?: (res: ClientResponse<R>) => unknown;
|
||||||
|
}>;
|
||||||
|
export declare type LazyRequestConfigFromEndpoint<E extends AnyEndpoint> = LazyRequestConfig<ExtractEndpointResponse<E>, ExtractEndpointVariables<E>, ExtractEndpointParams<E>>;
|
||||||
|
export declare type LazyRequestHandlerConfig<E extends AnyEndpoint> = Readonly<LazyRequestConfigFromEndpoint<E> & {
|
||||||
|
force?: boolean;
|
||||||
|
}>;
|
||||||
|
export declare type RequestHandler<E extends AnyEndpoint> = (config?: LazyRequestHandlerConfig<E>) => Promise<ExtractEndpointResponse<E> | null>;
|
||||||
|
export declare type PublicRequestStateWithActions<E extends AnyEndpoint> = PublicRequestState<ExtractEndpointResponse<E>> & {
|
||||||
|
refetch: () => void;
|
||||||
|
cancel: () => void;
|
||||||
|
};
|
||||||
|
export declare function useLazyRequest<E extends AnyEndpoint>(endpoint: E, config?: LazyRequestConfigFromEndpoint<E>): [RequestHandler<E>, PublicRequestStateWithActions<E>];
|
93
target/lazy_request_hook.js
Normal file
93
target/lazy_request_hook.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import React from 'react';
|
||||||
|
import invariant from 'tiny-invariant';
|
||||||
|
import isEqual from 'lodash.isequal';
|
||||||
|
import { useClient } from './client_hook';
|
||||||
|
import { requestReducer } from './reducer';
|
||||||
|
import { useRequestContext } from './request_context';
|
||||||
|
import { isFunction } from './misc';
|
||||||
|
export function useLazyRequest(endpoint, config) {
|
||||||
|
const [client] = useClient();
|
||||||
|
const { defaultHeaders } = useRequestContext();
|
||||||
|
const [state, dispatch] = React.useReducer(requestReducer, {
|
||||||
|
data: null,
|
||||||
|
loading: false,
|
||||||
|
isCalled: false,
|
||||||
|
});
|
||||||
|
const [prevHandlerConfig, setPrevHandlerConfig] = React.useState(null);
|
||||||
|
const transformResponseData = React.useCallback((data) => {
|
||||||
|
return isFunction(endpoint.transformResponseData) ?
|
||||||
|
endpoint.transformResponseData(data)
|
||||||
|
: data;
|
||||||
|
}, [endpoint]);
|
||||||
|
const handler = React.useCallback((handlerConfig) => {
|
||||||
|
var _a, _b, _c;
|
||||||
|
if ((state === null || state === void 0 ? void 0 : state.loading) || (state === null || state === void 0 ? void 0 : state.isCanceled)) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
let params;
|
||||||
|
let endpointUrl;
|
||||||
|
let isSameRequest = true;
|
||||||
|
if (isFunction(endpoint.url)) {
|
||||||
|
params = (_a = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.params) !== null && _a !== void 0 ? _a : config === null || config === void 0 ? void 0 : config.params;
|
||||||
|
invariant(params, 'Endpoint required params');
|
||||||
|
endpointUrl = endpoint.url(params);
|
||||||
|
isSameRequest = !!(state === null || state === void 0 ? void 0 : state.prevParams) && isEqual(state.prevParams, params);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
endpointUrl = endpoint.url;
|
||||||
|
}
|
||||||
|
const variables = Object.assign(Object.assign({}, config === null || config === void 0 ? void 0 : config.variables), handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.variables);
|
||||||
|
const headers = Object.assign(Object.assign(Object.assign(Object.assign({}, defaultHeaders), endpoint.headers), config === null || config === void 0 ? void 0 : config.headers), handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.headers);
|
||||||
|
if (state.isCalled
|
||||||
|
&& isSameRequest
|
||||||
|
&& (state === null || state === void 0 ? void 0 : state.prevVariables) && isEqual(state.prevVariables, variables)
|
||||||
|
&& (state === null || state === void 0 ? void 0 : state.prevHeaders) && isEqual(state.prevHeaders, headers)
|
||||||
|
&& !(handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.force)) {
|
||||||
|
return Promise.resolve(state.data);
|
||||||
|
}
|
||||||
|
const onComplete = (_b = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.onComplete) !== null && _b !== void 0 ? _b : config === null || config === void 0 ? void 0 : config.onComplete;
|
||||||
|
const onFailure = (_c = handlerConfig === null || handlerConfig === void 0 ? void 0 : handlerConfig.onFailure) !== null && _c !== void 0 ? _c : config === null || config === void 0 ? void 0 : config.onFailure;
|
||||||
|
dispatch({ type: 'call', headers, variables, params });
|
||||||
|
setPrevHandlerConfig(handlerConfig !== null && handlerConfig !== void 0 ? handlerConfig : {});
|
||||||
|
return client
|
||||||
|
.request(Object.assign(Object.assign({}, endpoint), { url: endpointUrl, headers,
|
||||||
|
variables,
|
||||||
|
transformResponseData }))
|
||||||
|
.then((response) => {
|
||||||
|
dispatch({ type: 'success', response });
|
||||||
|
if (isFunction(onComplete)) {
|
||||||
|
onComplete(response.data);
|
||||||
|
}
|
||||||
|
return response.data;
|
||||||
|
}, (response) => {
|
||||||
|
dispatch({ type: 'failure', response });
|
||||||
|
if (!response.canceled && isFunction(onFailure)) {
|
||||||
|
onFailure(response);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}, [state, config, client, endpoint, defaultHeaders, transformResponseData]);
|
||||||
|
const refetch = React.useCallback(() => {
|
||||||
|
if (prevHandlerConfig != null) {
|
||||||
|
handler(Object.assign(Object.assign({}, prevHandlerConfig), { force: true }));
|
||||||
|
}
|
||||||
|
}, [handler, prevHandlerConfig]);
|
||||||
|
React.useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
dispatch({ type: 'cancel' });
|
||||||
|
client.cancelRequest();
|
||||||
|
};
|
||||||
|
}, [client]);
|
||||||
|
return [
|
||||||
|
handler,
|
||||||
|
{
|
||||||
|
data: state.data,
|
||||||
|
loading: state.loading,
|
||||||
|
isCalled: state.isCalled,
|
||||||
|
isCanceled: state.isCanceled,
|
||||||
|
error: state.error,
|
||||||
|
refetch,
|
||||||
|
cancel: client.cancelRequest.bind(client),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
12
target/request_context.d.ts
vendored
Normal file
12
target/request_context.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Client } from './client';
|
||||||
|
export declare type RequestContextData = Readonly<{
|
||||||
|
client: Client;
|
||||||
|
defaultHeaders?: Record<string, string>;
|
||||||
|
}>;
|
||||||
|
export declare type RequestProviderProps = Readonly<React.PropsWithChildren<RequestContextData>>;
|
||||||
|
export declare function RequestProvider({ client, defaultHeaders, children }: RequestProviderProps): JSX.Element;
|
||||||
|
export declare function useRequestContext(): Readonly<{
|
||||||
|
client: Client;
|
||||||
|
defaultHeaders?: Record<string, string> | undefined;
|
||||||
|
}>;
|
11
target/request_context.js
Normal file
11
target/request_context.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import React from 'react';
|
||||||
|
import invariant from 'tiny-invariant';
|
||||||
|
const RequestContext = React.createContext(null);
|
||||||
|
export function RequestProvider({ client, defaultHeaders, children }) {
|
||||||
|
return (React.createElement(RequestContext.Provider, { value: { client, defaultHeaders } }, children));
|
||||||
|
}
|
||||||
|
export function useRequestContext() {
|
||||||
|
const context = React.useContext(RequestContext);
|
||||||
|
invariant(context, 'useRequestContext() must be a child of <RequestProvider />');
|
||||||
|
return context;
|
||||||
|
}
|
6
target/request_hook.d.ts
vendored
Normal file
6
target/request_hook.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { AnyEndpoint } from './endpoint';
|
||||||
|
import { LazyRequestConfigFromEndpoint } from './lazy_request_hook';
|
||||||
|
export declare type RequestConfigFromEndpoint<E extends AnyEndpoint> = Readonly<LazyRequestConfigFromEndpoint<E> & {
|
||||||
|
skip?: boolean;
|
||||||
|
}>;
|
||||||
|
export declare function useRequest<E extends AnyEndpoint>(endpoint: E, config?: RequestConfigFromEndpoint<E>): import("./lazy_request_hook").PublicRequestStateWithActions<E>;
|
15
target/request_hook.js
Normal file
15
target/request_hook.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import React from 'react';
|
||||||
|
import invariant from 'tiny-invariant';
|
||||||
|
import { Method } from './endpoint';
|
||||||
|
import { useLazyRequest } from './lazy_request_hook';
|
||||||
|
export function useRequest(endpoint, config) {
|
||||||
|
invariant(endpoint.method !== Method.DELETE, `You cannot use useRequest with ${endpoint.method} method`);
|
||||||
|
const [handler, state] = useLazyRequest(endpoint, config);
|
||||||
|
const skip = React.useMemo(() => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.skip) !== null && _a !== void 0 ? _a : false; }, [config]);
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!skip) {
|
||||||
|
handler();
|
||||||
|
}
|
||||||
|
}, [skip, handler]);
|
||||||
|
return state;
|
||||||
|
}
|
Reference in a new issue