@koine/api 2.0.0-beta.131 → 2.0.0-beta.133
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApiError.d.ts +7 -0
- package/createApi.d.ts +6 -0
- package/package.json +2 -2
- package/swr/createSwrApi.d.ts +22 -0
- package/swr-mutation/createSwrMutationApi.d.ts +3 -0
- package/types.d.ts +172 -0
package/ApiError.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { Api } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Custom `ApiError` class extending `Error` to throw in failed response.
|
|
4
|
+
*
|
|
5
|
+
* @see https://eslint.org/docs/rules/no-throw-literal
|
|
6
|
+
* @see https://github.com/sindresorhus/ky/blob/main/source/errors/HTTPError.ts
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
2
9
|
export declare class ApiError<TResponseFail extends Api.ResponseFail = unknown> extends Error {
|
|
3
10
|
constructor(result: Api.ResultFail<TResponseFail>);
|
|
4
11
|
}
|
package/createApi.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import type { Api } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Create api client
|
|
4
|
+
*
|
|
5
|
+
* @param apiName Short name to use in debug logs
|
|
6
|
+
* @param baseUrl Either relativ eor absolute, it must end without trailing slash
|
|
7
|
+
*/
|
|
2
8
|
export declare let createApi: <TEndpoints extends Api.Endpoints>(apiName: string, baseUrl: string, options?: Api.ClientOptions) => Api.Client<TEndpoints>;
|
|
3
9
|
export default createApi;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@koine/api",
|
|
3
3
|
"sideEffects": false,
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@koine/utils": "2.0.0-beta.
|
|
5
|
+
"@koine/utils": "2.0.0-beta.133"
|
|
6
6
|
},
|
|
7
7
|
"exports": {
|
|
8
8
|
"./swr/createSwrApi": {
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"module": "./index.esm.js",
|
|
89
89
|
"main": "./index.cjs.js",
|
|
90
90
|
"types": "./index.esm.d.ts",
|
|
91
|
-
"version": "2.0.0-beta.
|
|
91
|
+
"version": "2.0.0-beta.133"
|
|
92
92
|
}
|
package/swr/createSwrApi.d.ts
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
import { type BareFetcher, type SWRConfiguration, type SWRResponse } from "swr";
|
|
2
2
|
import type { Api } from "../types";
|
|
3
3
|
type SWRConfigurationExtended<Data = any, Error = any, Fn extends BareFetcher<any> = BareFetcher<any>> = SWRConfiguration<Data, Error, Fn> & {
|
|
4
|
+
/**
|
|
5
|
+
* Conditional fetching as option
|
|
6
|
+
*
|
|
7
|
+
* Moving this to an option allows us to keep the endpoints typed dictionary,
|
|
8
|
+
* e.g. we can write:
|
|
9
|
+
*
|
|
10
|
+
* ```js
|
|
11
|
+
* const { data, mutate } = myApi.use("User/{id}",
|
|
12
|
+
* { params: { id: aVariableMaybeContainingAnId || "" }, },
|
|
13
|
+
* { when: !!aVariableMaybeContainingAnId }
|
|
14
|
+
* );
|
|
15
|
+
*
|
|
16
|
+
* // we still have typed `data`, `mutate`
|
|
17
|
+
* ```
|
|
18
|
+
* @see https://swr.vercel.app/docs/conditional-fetching
|
|
19
|
+
*/
|
|
4
20
|
when?: boolean | (() => boolean);
|
|
5
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
6
25
|
export declare let createUseApi: <TEndpoints extends Api.Endpoints>(api: Api.Client<TEndpoints>) => <TEndpoint extends Api.EndpointUrl<TEndpoints>>(endpoint: TEndpoint, options?: Api.EndpointOptions<TEndpoints, TEndpoint, "get">, config?: SWRConfigurationExtended<Api.EndpointResponseOk<TEndpoints, TEndpoint, "get">, Api.EndpointResponseFail<TEndpoints, TEndpoint, "get">>) => SWRResponse<Api.EndpointResponseOk<TEndpoints, TEndpoint, "get">, Api.EndpointResponseFail<TEndpoints, TEndpoint, "get">>;
|
|
26
|
+
/**
|
|
27
|
+
* It creates an api client extended with auto-generated SWR wrapper hooks
|
|
28
|
+
*/
|
|
7
29
|
export declare let createSwrApi: <TEndpoints extends Api.Endpoints>(apiName: string, baseUrl: string, options?: Api.ClientOptions | undefined) => Api.Client<TEndpoints> & {
|
|
8
30
|
use: ReturnType<typeof createUseApi<TEndpoints>>;
|
|
9
31
|
};
|
|
@@ -4,6 +4,9 @@ import type { Api } from "../types";
|
|
|
4
4
|
type MutationRequestMethod = Exclude<Api.RequestMethod, "get">;
|
|
5
5
|
type MutationHookName = Exclude<keyof Api.HooksMapsByName, "use">;
|
|
6
6
|
type KoineApiMethodHookSWR<THookName extends MutationHookName, TEndpoints extends Api.Endpoints> = <TEndpoint extends Api.EndpointUrl<TEndpoints>, TMethod extends MutationRequestMethod = Api.HooksMapsByName[THookName]>(endpoint: TEndpoint, options?: Api.EndpointOptions<TEndpoints, TEndpoint, TMethod>, config?: SWRMutationConfiguration<Api.EndpointResponseOk<TEndpoints, TEndpoint, TMethod>, Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>, TEndpoint, Api.EndpointOptions<TEndpoints, TEndpoint, TMethod>>) => SWRMutationResponse<Api.EndpointResponseOk<TEndpoints, TEndpoint, TMethod>, Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>, TEndpoint, Api.EndpointOptions<TEndpoints, TEndpoint, TMethod>>;
|
|
7
|
+
/**
|
|
8
|
+
* It creates an api client extended with auto-generated SWR wrapper hooks
|
|
9
|
+
*/
|
|
7
10
|
export declare let createSwrMutationApi: <TEndpoints extends Api.Endpoints>(apiName: string, baseUrl: string, options?: Api.ClientOptions | undefined) => Api.Client<TEndpoints> & {
|
|
8
11
|
usePost: KoineApiMethodHookSWR<"usePost", TEndpoints>;
|
|
9
12
|
usePut: KoineApiMethodHookSWR<"usePut", TEndpoints>;
|
package/types.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
type _Response = Response;
|
|
2
|
+
/**
|
|
3
|
+
* @borrows [awesome-template-literal-types](https://github.com/ghoullier/awesome-template-literal-types#router-params-parsing)
|
|
4
|
+
*/
|
|
2
5
|
type ExtractEndpointParams<T extends string> = string | number extends T ? Record<string, string> : T extends `${infer _Start}{${infer Param}}${infer Rest}` ? {
|
|
3
6
|
[k in Param | keyof ExtractEndpointParams<Rest>]: string | number;
|
|
4
7
|
} : T extends `${infer _Start}{${infer Param}}` ? {
|
|
@@ -6,15 +9,60 @@ type ExtractEndpointParams<T extends string> = string | number extends T ? Recor
|
|
|
6
9
|
} : {};
|
|
7
10
|
export declare namespace Api {
|
|
8
11
|
export type ClientOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* Headers will be merged with
|
|
14
|
+
* ```
|
|
15
|
+
* { "content-type": "application/json" }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @default {}
|
|
19
|
+
*/
|
|
9
20
|
headers?: RequestInit["headers"];
|
|
21
|
+
/**
|
|
22
|
+
* Basic request options to supply to `fetch`
|
|
23
|
+
*
|
|
24
|
+
* @see RequestInit
|
|
25
|
+
*
|
|
26
|
+
* @default {}
|
|
27
|
+
*/
|
|
10
28
|
request?: Omit<RequestInit, "body" | "headers" | "method">;
|
|
29
|
+
/**
|
|
30
|
+
* Flag to throw error within the catch block, by default we return a
|
|
31
|
+
* normalised error result {@link ResultFail}
|
|
32
|
+
*
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
11
35
|
throwErr?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Timeout in `ms`, if `falsy` there is no timeout
|
|
38
|
+
*
|
|
39
|
+
* @default 10000
|
|
40
|
+
*/
|
|
12
41
|
timeout?: number | false | null;
|
|
42
|
+
/**
|
|
43
|
+
* Process request before actual http call
|
|
44
|
+
*
|
|
45
|
+
* @default undefined
|
|
46
|
+
*/
|
|
13
47
|
processReq?: RequestProcessor;
|
|
48
|
+
/**
|
|
49
|
+
* Process ok/failed response just after http response
|
|
50
|
+
*
|
|
51
|
+
* @default undefined
|
|
52
|
+
*/
|
|
14
53
|
processRes?: ResponseProcessorRes;
|
|
54
|
+
/**
|
|
55
|
+
* Process maybe-thrown error originated either from `fetch` function
|
|
56
|
+
* invokation or from its `response.json()` parsing
|
|
57
|
+
*
|
|
58
|
+
* @default undefined
|
|
59
|
+
*/
|
|
15
60
|
processErr?: ResponseProcessorErr;
|
|
16
61
|
};
|
|
17
62
|
type ClientMethod<TMethod extends RequestMethod, TEndpoints extends Endpoints> = <TEndpoint extends EndpointUrl<TEndpoints>, TOptions extends EndpointOptions<TEndpoints, TEndpoint, TMethod>, TOk extends ResponseOk = EndpointResponseOk<TEndpoints, TEndpoint, TMethod>, TFail extends ResponseFail = EndpointResponseFail<TEndpoints, TEndpoint, TMethod>>(endpoint: TEndpoint, options?: TOptions) => Promise<EndpointResult<TEndpoints, TEndpoint, TMethod>>;
|
|
63
|
+
/**
|
|
64
|
+
* The `api` interface generated by `createApi`
|
|
65
|
+
*/
|
|
18
66
|
export type Client<TEndpoints extends Endpoints> = {
|
|
19
67
|
[TMethod in RequestMethod]: ClientMethod<TMethod, TEndpoints>;
|
|
20
68
|
};
|
|
@@ -29,19 +77,51 @@ export declare namespace Api {
|
|
|
29
77
|
};
|
|
30
78
|
export type EndpointUrl<TEndpoints extends Endpoints> = Extract<keyof TEndpoints, string>;
|
|
31
79
|
type DataTypes<TMethod extends Uppercase<RequestMethod>> = {
|
|
80
|
+
/**
|
|
81
|
+
* The request body of a non-GET request
|
|
82
|
+
*/
|
|
32
83
|
json?: RequestJson;
|
|
84
|
+
/**
|
|
85
|
+
* The parameters to encode in the URL of the request
|
|
86
|
+
*/
|
|
33
87
|
query?: RequestQuery;
|
|
88
|
+
/**
|
|
89
|
+
* The JSON response data returned by the request in case of success
|
|
90
|
+
*/
|
|
34
91
|
ok?: null | unknown;
|
|
92
|
+
/**
|
|
93
|
+
* The shape of the error data returned by the request in case of
|
|
94
|
+
* failure
|
|
95
|
+
*/
|
|
35
96
|
fail?: null | unknown;
|
|
36
97
|
};
|
|
37
98
|
export type RequestMethod = "get" | "post" | "put" | "patch" | "delete";
|
|
38
99
|
type RequestJson = unknown;
|
|
39
100
|
type RequestQuery = unknown;
|
|
40
101
|
type RequestParams = unknown;
|
|
102
|
+
/**
|
|
103
|
+
* Request options
|
|
104
|
+
*
|
|
105
|
+
* `ClientOptions` can be overriden here at the single request level.
|
|
106
|
+
*/
|
|
41
107
|
type RequestOptions<TEndpoints extends Endpoints, TEndpoint extends EndpointUrl<TEndpoints>, TMethod extends RequestMethod, TJson extends RequestJson, TQuery extends RequestQuery> = Omit<ClientOptions, "processReq"> & {
|
|
42
108
|
processReq?: EndpointRequestProcessor<TEndpoints, TEndpoint, TMethod>;
|
|
109
|
+
/**
|
|
110
|
+
* A dictionary to dynamically interpolate endpoint url params, e.g.:
|
|
111
|
+
*
|
|
112
|
+
* ```js
|
|
113
|
+
* myapi.get("user/{id}", { params: { id: "12" }})
|
|
114
|
+
* ```
|
|
115
|
+
* results in a call to the endpoint `"user/12"`
|
|
116
|
+
*/
|
|
43
117
|
params?: ExtractEndpointParams<TEndpoint>;
|
|
118
|
+
/**
|
|
119
|
+
* Query parameters will be serialized into a string and appended to the URL
|
|
120
|
+
*/
|
|
44
121
|
query?: TQuery;
|
|
122
|
+
/**
|
|
123
|
+
* JSON request body
|
|
124
|
+
*/
|
|
45
125
|
json?: TJson;
|
|
46
126
|
};
|
|
47
127
|
export type ResponseOk = unknown;
|
|
@@ -73,6 +153,10 @@ export declare namespace Api {
|
|
|
73
153
|
fail: true;
|
|
74
154
|
data: TResponseFail;
|
|
75
155
|
};
|
|
156
|
+
/**
|
|
157
|
+
* The request processor at the client level, this is meant to apply global
|
|
158
|
+
* transformations to all endpoints requests
|
|
159
|
+
*/
|
|
76
160
|
export type RequestProcessor = (method: RequestMethod, url: string, query: any, json: any, params: any, requestInit: RequestInit) => [
|
|
77
161
|
string,
|
|
78
162
|
RequestQuery,
|
|
@@ -80,6 +164,13 @@ export declare namespace Api {
|
|
|
80
164
|
RequestParams,
|
|
81
165
|
RequestInit
|
|
82
166
|
];
|
|
167
|
+
/**
|
|
168
|
+
* The request processor at the request level, this is meant to apply
|
|
169
|
+
* transformations to a single endpoint request. Request processor applied at
|
|
170
|
+
* the whole client level is still applied just before this one, hence one
|
|
171
|
+
* might set some global processing and override it or undo it at the single
|
|
172
|
+
* request level.
|
|
173
|
+
*/
|
|
83
174
|
export type EndpointRequestProcessor<TEndpoints extends Endpoints, TEndpoint extends EndpointUrl<TEndpoints>, TMethod extends RequestMethod> = (method: TMethod, url: string, query: EndpointOptions<TEndpoints, TEndpoint, TMethod>["query"], json: EndpointOptions<TEndpoints, TEndpoint, TMethod>["json"], params: EndpointOptions<TEndpoints, TEndpoint, TMethod>["params"], requestInit: RequestInit) => [
|
|
84
175
|
string,
|
|
85
176
|
EndpointOptions<TEndpoints, TEndpoint, TMethod>["query"],
|
|
@@ -87,8 +178,23 @@ export declare namespace Api {
|
|
|
87
178
|
EndpointOptions<TEndpoints, TEndpoint, TMethod>["params"],
|
|
88
179
|
RequestInit
|
|
89
180
|
];
|
|
181
|
+
/**
|
|
182
|
+
* The ok/fail response processor at the request level, this is meant to apply
|
|
183
|
+
* transformations to a single or all endpoint responses
|
|
184
|
+
*/
|
|
90
185
|
type ResponseProcessorRes = <TResponseOk extends ResponseOk = ResponseOk, TResponseFail extends ResponseFail = ResponseFail>(response: _Response, options: any) => Promise<Result<TResponseOk, TResponseFail>>;
|
|
186
|
+
/**
|
|
187
|
+
* The error response processor at the request level, this is meant to apply
|
|
188
|
+
* transformations to a single or all endpoint responses
|
|
189
|
+
*/
|
|
91
190
|
type ResponseProcessorErr = <TResponseOk extends ResponseOk = ResponseOk, TResponseFail extends ResponseFail = ResponseFail>(msg: string, options: any) => Promise<Result<TResponseOk, TResponseFail>>;
|
|
191
|
+
/**
|
|
192
|
+
* Api hooks map for `react`, each request method has its own `use{Method}`
|
|
193
|
+
* hook.
|
|
194
|
+
*
|
|
195
|
+
* These hooks are implemented with different libraries or, in the future as
|
|
196
|
+
* standalone hooks, see SWR ones to start with.
|
|
197
|
+
*/
|
|
92
198
|
type HooksMaps = {
|
|
93
199
|
[TMethod in RequestMethod]: `use${TMethod extends "get" ? "" : Capitalize<TMethod>}`;
|
|
94
200
|
};
|
|
@@ -97,7 +203,33 @@ export declare namespace Api {
|
|
|
97
203
|
};
|
|
98
204
|
export {};
|
|
99
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* To generate all available helpers use in your `API` types:
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```ts
|
|
211
|
+
* type Response = Api.Generate.ResponseHelpers<Endpoints>;
|
|
212
|
+
* type Request = Api.Generate.RequestHelpers<Endpoints>;
|
|
213
|
+
* type Get = Api.Generate.GetHelpers<Endpoints>;
|
|
214
|
+
* type Post = Api.Generate.PostHelpers<Endpoints>;
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
100
217
|
export declare namespace Api.Generate {
|
|
218
|
+
/**
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* // define the type on your `API` types:
|
|
222
|
+
* type Result = Api.Generate.ResultShortcuts<Endpoints>;
|
|
223
|
+
*
|
|
224
|
+
* // consume the type wherever in your app:
|
|
225
|
+
* type MyResult = API.Result["get"]["my/endpoint"];
|
|
226
|
+
*
|
|
227
|
+
* MyResult["ok"];
|
|
228
|
+
* ^
|
|
229
|
+
* MyResult["fail"];
|
|
230
|
+
* ^
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
101
233
|
type ResultShortcuts<TEndpoints extends Endpoints> = {
|
|
102
234
|
[TMethod in RequestMethod]: {
|
|
103
235
|
[TEndpoint in Extract<keyof TEndpoints, string>]: {
|
|
@@ -106,19 +238,59 @@ export declare namespace Api.Generate {
|
|
|
106
238
|
};
|
|
107
239
|
};
|
|
108
240
|
};
|
|
241
|
+
/**
|
|
242
|
+
* @example
|
|
243
|
+
* ```ts
|
|
244
|
+
* // define the type on your `API` types:
|
|
245
|
+
* type Response = Api.Generate.ResponseShortcuts<Endpoints>;
|
|
246
|
+
*
|
|
247
|
+
* // consume the type wherever in your app:
|
|
248
|
+
* type MyData = API.Response["get"]["my/endpoint"];
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
109
251
|
type ResponseShortcuts<TEndpoints extends Endpoints> = {
|
|
110
252
|
[TMethod in RequestMethod]: {
|
|
111
253
|
[TEndpoint in Extract<keyof TEndpoints, string>]: GetDataType<TEndpoints, TEndpoint, TMethod, "ok">;
|
|
112
254
|
};
|
|
113
255
|
};
|
|
256
|
+
/**
|
|
257
|
+
* @example
|
|
258
|
+
* ```ts
|
|
259
|
+
* // define the type on your `API` types:
|
|
260
|
+
* type Request = Api.Generate.RequestShortcuts<Endpoints>;
|
|
261
|
+
*
|
|
262
|
+
* // consume the type wherever in your app:
|
|
263
|
+
* type MyData = API.Request["get"]["my/endpoint"];
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
114
266
|
type RequestShortcuts<TEndpoints extends Endpoints> = {
|
|
115
267
|
[TMethod in RequestMethod]: {
|
|
116
268
|
[TEndpoint in Extract<keyof TEndpoints, string>]: TMethod extends "get" ? GetDataType<TEndpoints, TEndpoint, TMethod, "query"> : GetDataType<TEndpoints, TEndpoint, TMethod, "json">;
|
|
117
269
|
};
|
|
118
270
|
};
|
|
271
|
+
/**
|
|
272
|
+
* @example
|
|
273
|
+
* ```ts
|
|
274
|
+
* // define the type on your `API` types:
|
|
275
|
+
* type Get = Api.Generate.ResponseShortcuts<Endpoints>;
|
|
276
|
+
*
|
|
277
|
+
* // consume the type wherever in your app:
|
|
278
|
+
* type MyData = API.Get["my/endpoint"];
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
119
281
|
type GetShortcuts<TEndpoints extends Endpoints> = {
|
|
120
282
|
[TEndpoint in Extract<keyof TEndpoints, string>]: GetDataType<TEndpoints, TEndpoint, "get", "ok">;
|
|
121
283
|
};
|
|
284
|
+
/**
|
|
285
|
+
* @example
|
|
286
|
+
* ```ts
|
|
287
|
+
* // define the type on your `API` types:
|
|
288
|
+
* type Post = Api.Generate.ResponseShortcuts<Endpoints>;
|
|
289
|
+
*
|
|
290
|
+
* // consume the type wherever in your app:
|
|
291
|
+
* type MyData = API.Post["my/endpoint"];
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
122
294
|
type PostShortcuts<TEndpoints extends Endpoints> = {
|
|
123
295
|
[TEndpoint in Extract<keyof TEndpoints, string>]: GetDataType<TEndpoints, TEndpoint, "post", "ok">;
|
|
124
296
|
};
|