diff --git a/package-lock.json b/package-lock.json index c71c4e0..64d6bfd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "react-rest-request", - "version": "0.4.1", + "version": "0.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -5083,7 +5083,8 @@ "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true }, "js-yaml": { "version": "3.13.1", @@ -5340,14 +5341,6 @@ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "^3.0.0" - } - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -5624,7 +5617,8 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object-copy": { "version": "0.1.0", @@ -6256,15 +6250,6 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, - "react": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", - "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "react-is": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", diff --git a/package.json b/package.json index ff0b84d..b1d0cd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-rest-request", - "version": "0.4.1", + "version": "0.5.3", "description": "Minimalistic REST API client for React inspired by Apollo", "readme": "README.md", "main": "./target/index.js", diff --git a/src/endpoint.ts b/src/endpoint.ts index 70568b0..520cf9f 100644 --- a/src/endpoint.ts +++ b/src/endpoint.ts @@ -8,13 +8,16 @@ export enum Method { DELETE = 'DELETE', } -export type Endpoint = Readonly<{ +export type Endpoint = Readonly<{ + _?: V; // Temporary hack to extract the type of variables. Do not use it in real endpoints. method: Method; url: string | ((params: P) => string); headers?: Record; transformResponseData?: (data: any) => R; }> +export type AnyEndpoint = Endpoint + export type ExtractEndpointResponse = E extends Endpoint ? R : E extends Endpoint ? R : never; export type ExtractEndpointVariables = E extends Endpoint ? V : E extends Endpoint ? V : never; export type ExtractEndpointParams = E extends Endpoint ? P : never; diff --git a/src/lazy-request-hook.ts b/src/lazy-request-hook.ts index c9c807d..53e7cb4 100644 --- a/src/lazy-request-hook.ts +++ b/src/lazy-request-hook.ts @@ -2,13 +2,13 @@ import React from 'react'; import invariant from 'tiny-invariant'; import isEqual from 'lodash.isequal'; import { useClient } from './client-hook'; -import { Endpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; -import { PublicRequestState, RequestAction, requestReducer, RequestState } from './reducer'; +import { AnyEndpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; +import { PublicRequestState, RequestReducer, requestReducer } from './reducer'; import { useRequestContext } from './request-context'; import { ClientResponse } from './client'; import { isFunction } from './misc'; -export type LazyRequestConfig = Readonly<{ +export type LazyRequestConfig = Readonly<{ variables?: V; params?: P; headers?: Record; @@ -16,29 +16,33 @@ export type LazyRequestConfig = Readonly<{ onFailure?: (res: ClientResponse) => unknown; }> -export type LazyRequestHandlerConfig = Readonly< - LazyRequestConfig +export type LazyRequestConfigFromEndpoint = LazyRequestConfig< + ExtractEndpointResponse, + ExtractEndpointVariables, + ExtractEndpointParams +>; + +export type LazyRequestHandlerConfig = Readonly< + LazyRequestConfigFromEndpoint & { force?: boolean } > -export type RequestHandler = (config?: LazyRequestHandlerConfig) => Promise; +export type RequestHandler = + (config?: LazyRequestHandlerConfig) => Promise | null>; export type RefetchRequestHandler = () => void; -export type PublicRequestStateWithRefetch = PublicRequestState & { refetch: RefetchRequestHandler }; +export type PublicRequestStateWithRefetch = + PublicRequestState> + & { refetch: RefetchRequestHandler }; -export function useLazyRequest< - E extends Endpoint, - R = ExtractEndpointResponse, - V = ExtractEndpointVariables, - P = ExtractEndpointParams ->( +export function useLazyRequest( endpoint: E, - config?: LazyRequestConfig, -): [RequestHandler, PublicRequestStateWithRefetch] { + config?: LazyRequestConfigFromEndpoint, +): [RequestHandler, PublicRequestStateWithRefetch] { const [client] = useClient(); const { defaultHeaders } = useRequestContext(); - const [state, dispatch] = React.useReducer, RequestAction>>( + const [state, dispatch] = React.useReducer>>( requestReducer, { data: null, @@ -46,24 +50,24 @@ export function useLazyRequest< isCalled: false, } ); - const [prevHandlerConfig, setPrevHandlerConfig] = React.useState | null>(null); + const [prevHandlerConfig, setPrevHandlerConfig] = React.useState | null>(null); const transformResponseData = React.useCallback( - (data: unknown): R => { + (data: unknown): ExtractEndpointResponse => { return isFunction(endpoint.transformResponseData) ? endpoint.transformResponseData(data) - : data as R; + : data as ExtractEndpointResponse; }, [endpoint] ); const handler = React.useCallback( - (handlerConfig?: LazyRequestHandlerConfig) => { + (handlerConfig?: LazyRequestHandlerConfig) => { if (state?.loading) { return Promise.resolve(null); } - let params: P | undefined; + let params: ExtractEndpointParams | undefined; let endpointUrl: string; let isSameRequest = true; if (isFunction(endpoint.url)) { @@ -106,7 +110,7 @@ export function useLazyRequest< setPrevHandlerConfig(handlerConfig ?? {}); return client - .request({ + .request>({ ...endpoint, url: endpointUrl, headers, diff --git a/src/reducer.ts b/src/reducer.ts index 5607fcf..409ef63 100644 --- a/src/reducer.ts +++ b/src/reducer.ts @@ -28,6 +28,8 @@ export type RequestAction = response: ClientResponse } +export type RequestReducer = React.Reducer, RequestAction> + export function requestReducer(state: RequestState, action: RequestAction) { switch (action.type) { case 'call': { diff --git a/src/request-hook.ts b/src/request-hook.ts index 376e529..a66ed8a 100644 --- a/src/request-hook.ts +++ b/src/request-hook.ts @@ -1,23 +1,18 @@ import React from 'react'; import invariant from 'tiny-invariant'; -import { Endpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables, Method } from './endpoint'; -import { LazyRequestConfig, useLazyRequest } from './lazy-request-hook'; +import { AnyEndpoint, Method } from './endpoint'; +import { LazyRequestConfigFromEndpoint, useLazyRequest } from './lazy-request-hook'; -export type RequestConfig = Readonly< - LazyRequestConfig +export type RequestConfigFromEndpoint = Readonly< + LazyRequestConfigFromEndpoint & { skip?: boolean, } > -export function useRequest< - E extends Endpoint, - R = ExtractEndpointResponse, - V = ExtractEndpointVariables, - P = ExtractEndpointParams ->( +export function useRequest( endpoint: E, - config?: RequestConfig, + config?: RequestConfigFromEndpoint, ) { invariant( endpoint.method !== Method.DELETE, diff --git a/target/endpoint.d.ts b/target/endpoint.d.ts index 3fb8732..54e2b09 100644 --- a/target/endpoint.d.ts +++ b/target/endpoint.d.ts @@ -6,12 +6,14 @@ export declare enum Method { PATCH = "PATCH", DELETE = "DELETE" } -export declare type Endpoint = Readonly<{ +export declare type Endpoint = Readonly<{ + _?: V; method: Method; url: string | ((params: P) => string); headers?: Record; transformResponseData?: (data: any) => R; }>; +export declare type AnyEndpoint = Endpoint; export declare type ExtractEndpointResponse = E extends Endpoint ? R : E extends Endpoint ? R : never; export declare type ExtractEndpointVariables = E extends Endpoint ? V : E extends Endpoint ? V : never; export declare type ExtractEndpointParams = E extends Endpoint ? P : never; diff --git a/target/lazy-request-hook.d.ts b/target/lazy-request-hook.d.ts index 34e8248..85eb71d 100644 --- a/target/lazy-request-hook.d.ts +++ b/target/lazy-request-hook.d.ts @@ -1,19 +1,20 @@ -import { Endpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; +import { AnyEndpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; import { PublicRequestState } from './reducer'; import { ClientResponse } from './client'; -export declare type LazyRequestConfig = Readonly<{ +export declare type LazyRequestConfig = Readonly<{ variables?: V; params?: P; headers?: Record; onComplete?: (data: R) => unknown; onFailure?: (res: ClientResponse) => unknown; }>; -export declare type LazyRequestHandlerConfig = Readonly & { +export declare type LazyRequestConfigFromEndpoint = LazyRequestConfig, ExtractEndpointVariables, ExtractEndpointParams>; +export declare type LazyRequestHandlerConfig = Readonly & { force?: boolean; }>; -export declare type RequestHandler = (config?: LazyRequestHandlerConfig) => Promise; +export declare type RequestHandler = (config?: LazyRequestHandlerConfig) => Promise | null>; export declare type RefetchRequestHandler = () => void; -export declare type PublicRequestStateWithRefetch = PublicRequestState & { +export declare type PublicRequestStateWithRefetch = PublicRequestState> & { refetch: RefetchRequestHandler; }; -export declare function useLazyRequest, R = ExtractEndpointResponse, V = ExtractEndpointVariables, P = ExtractEndpointParams>(endpoint: E, config?: LazyRequestConfig): [RequestHandler, PublicRequestStateWithRefetch]; +export declare function useLazyRequest(endpoint: E, config?: LazyRequestConfigFromEndpoint): [RequestHandler, PublicRequestStateWithRefetch]; diff --git a/target/reducer.d.ts b/target/reducer.d.ts index 0b0892f..bf94a2c 100644 --- a/target/reducer.d.ts +++ b/target/reducer.d.ts @@ -1,3 +1,4 @@ +/// import { ClientResponse } from './client'; export declare type PublicRequestState = Readonly<{ data: R | null; @@ -21,6 +22,7 @@ export declare type RequestAction = { type: 'failure'; response: ClientResponse; }; +export declare type RequestReducer = React.Reducer, RequestAction>; export declare function requestReducer(state: RequestState, action: RequestAction): { loading: boolean; isCalled: boolean; diff --git a/target/request-hook.d.ts b/target/request-hook.d.ts index 0644b01..23106ca 100644 --- a/target/request-hook.d.ts +++ b/target/request-hook.d.ts @@ -1,6 +1,6 @@ -import { Endpoint, ExtractEndpointParams, ExtractEndpointResponse, ExtractEndpointVariables } from './endpoint'; -import { LazyRequestConfig } from './lazy-request-hook'; -export declare type RequestConfig = Readonly & { +import { AnyEndpoint } from './endpoint'; +import { LazyRequestConfigFromEndpoint } from './lazy-request-hook'; +export declare type RequestConfigFromEndpoint = Readonly & { skip?: boolean; }>; -export declare function useRequest, R = ExtractEndpointResponse, V = ExtractEndpointVariables, P = ExtractEndpointParams>(endpoint: E, config?: RequestConfig): import("./lazy-request-hook").PublicRequestStateWithRefetch; +export declare function useRequest(endpoint: E, config?: RequestConfigFromEndpoint): import("./lazy-request-hook").PublicRequestStateWithRefetch;