typedapi-client-helpers 0.1.11 → 0.1.13
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/README.md +189 -57
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/package.json +1 -1
- package/scripts/generate-api-minimal.mjs +121 -166
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ Configuration can be supplied in the `config` section of your `package.json`, wi
|
|
|
68
68
|
| `apiOutput` | `src/api` | Directory where the generated API files are written. |
|
|
69
69
|
| `typedApiUseTypeOnlyImports` | `false` | Generates `import type` statements for imports that are only used as types. |
|
|
70
70
|
| `typedApiUseFilterFormValues` | `false` | Generates paginated methods that accept `FilterFormValues[]`, page values, and sort values instead of a prebuilt query object. |
|
|
71
|
-
| `typedApiDefaultFunctionsPath` | `
|
|
71
|
+
| `typedApiDefaultFunctionsPath` | `defaultApiFunctions` | Import path used by generated method files for shared success and error handlers. |
|
|
72
72
|
| `typedApiDefaultSuccessHandler` | `handleGoodResult` | Name of the default success handler function imported into generated methods. |
|
|
73
73
|
| `typedApiDefaultErrorHandler` | `handleErrors` | Name of the default error handler function imported into generated methods. |
|
|
74
74
|
|
|
@@ -118,12 +118,12 @@ src/
|
|
|
118
118
|
└── index.ts
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
| Folder or file | Description
|
|
122
|
-
| ------------------------ |
|
|
123
|
-
| `generated/` | Raw client, models,
|
|
124
|
-
| `methods/` | Typed wrapper methods generated by this package. These call the raw generated client and return `ApiResult<T>`.
|
|
125
|
-
| `index.ts` | Barrel file that exports generated contracts, HTTP client types, and wrapper methods.
|
|
126
|
-
| `defaultApiFunctions.ts` | Optional shared success and error handlers created when the configured default handler file does not exist.
|
|
121
|
+
| Folder or file | Description |
|
|
122
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
|
|
123
|
+
| `generated/` | Raw client, models, and HTTP client generated by `swagger-typescript-api`. Route type files are removed after generation. |
|
|
124
|
+
| `methods/` | Typed wrapper methods generated by this package. These call the raw generated client and return `ApiResult<T>`. |
|
|
125
|
+
| `index.ts` | Barrel file that exports generated contracts, HTTP client types, and wrapper methods. |
|
|
126
|
+
| `defaultApiFunctions.ts` | Optional shared success and error handlers created when the configured default handler file does not exist. |
|
|
127
127
|
|
|
128
128
|
## Calling generated methods
|
|
129
129
|
|
|
@@ -148,36 +148,84 @@ Checking `result.ok` narrows the result automatically.
|
|
|
148
148
|
|
|
149
149
|
## Generated method argument order
|
|
150
150
|
|
|
151
|
-
Generated wrappers preserve the original generated API arguments and then add optional
|
|
151
|
+
Generated wrappers preserve the original generated API arguments and then add an optional method options object.
|
|
152
152
|
|
|
153
153
|
For query methods:
|
|
154
154
|
|
|
155
155
|
```ts
|
|
156
|
-
await getSuppliers(query,
|
|
156
|
+
await getSuppliers(query, {
|
|
157
|
+
onSuccess,
|
|
158
|
+
onError,
|
|
159
|
+
params,
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
For query methods without a query object, pass `undefined` as the first argument when you want to provide options:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
await exportPartners(undefined, {
|
|
167
|
+
onError: handleError,
|
|
168
|
+
});
|
|
157
169
|
```
|
|
158
170
|
|
|
159
171
|
For non-query methods:
|
|
160
172
|
|
|
161
173
|
```ts
|
|
162
|
-
await updateSupplier(id, body,
|
|
174
|
+
await updateSupplier(id, body, {
|
|
175
|
+
onSuccess,
|
|
176
|
+
onError,
|
|
177
|
+
params,
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
For multipart/form-data methods:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
await uploadSupplierLogo(data, {
|
|
185
|
+
onSuccess,
|
|
186
|
+
onError,
|
|
187
|
+
params,
|
|
188
|
+
});
|
|
163
189
|
```
|
|
164
190
|
|
|
165
191
|
For filter-form paginated methods when `typedApiUseFilterFormValues` is enabled:
|
|
166
192
|
|
|
167
193
|
```ts
|
|
168
|
-
await getSuppliers(
|
|
169
|
-
filters,
|
|
170
|
-
page,
|
|
171
|
-
pageSize,
|
|
172
|
-
sortBy,
|
|
173
|
-
sortDirection,
|
|
194
|
+
await getSuppliers(filters, page, pageSize, sortBy, sortDirection, {
|
|
174
195
|
onSuccess,
|
|
175
196
|
onError,
|
|
176
197
|
params,
|
|
177
|
-
);
|
|
198
|
+
});
|
|
178
199
|
```
|
|
179
200
|
|
|
180
|
-
The
|
|
201
|
+
The `params` property is forwarded to the generated HTTP client and can contain values such as headers or other request options.
|
|
202
|
+
|
|
203
|
+
Every generated wrapper method gets its own options type. The type name is based on the method name.
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
export type GetSuppliersOptions = {
|
|
207
|
+
onSuccess?: ApiSuccessHandler<GetSuppliersResponse>;
|
|
208
|
+
onError?: ApiErrorHandler<GetSuppliersError>;
|
|
209
|
+
params?: RequestParams;
|
|
210
|
+
};
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Examples of generated option type names:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
GetSuppliersOptions;
|
|
217
|
+
CreateSupplierOptions;
|
|
218
|
+
UpdateSupplierOptions;
|
|
219
|
+
ExportPartnersOptions;
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
This makes it possible to pass only `onError` without also passing `onSuccess`.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
await getSuppliers(undefined, {
|
|
226
|
+
onError: handleError,
|
|
227
|
+
});
|
|
228
|
+
```
|
|
181
229
|
|
|
182
230
|
## Success and error callbacks
|
|
183
231
|
|
|
@@ -195,28 +243,98 @@ function onError(result: ApiErrorResult<SupplierListResponse>) {
|
|
|
195
243
|
console.error(result.status, result.error);
|
|
196
244
|
}
|
|
197
245
|
|
|
198
|
-
await getSuppliers(
|
|
246
|
+
await getSuppliers(
|
|
247
|
+
{ pageNumber: 1, pageSize: 25 },
|
|
248
|
+
{
|
|
249
|
+
onSuccess,
|
|
250
|
+
onError,
|
|
251
|
+
},
|
|
252
|
+
);
|
|
199
253
|
```
|
|
200
254
|
|
|
201
255
|
The generated method still returns `ApiResult<T>` after callbacks run.
|
|
202
256
|
|
|
257
|
+
You can also pass only one callback.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
await getSuppliers(
|
|
261
|
+
{ pageNumber: 1, pageSize: 25 },
|
|
262
|
+
{
|
|
263
|
+
onError,
|
|
264
|
+
},
|
|
265
|
+
);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
When default handlers are configured, generated methods use them when no method-specific callback is supplied.
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
await getSuppliers(
|
|
272
|
+
{ pageNumber: 1, pageSize: 25 },
|
|
273
|
+
{
|
|
274
|
+
onSuccess: customSuccessHandler,
|
|
275
|
+
},
|
|
276
|
+
);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
In this example, the custom success handler is used for success results, and the configured default error handler is still used for error results.
|
|
280
|
+
|
|
203
281
|
## Custom request parameters
|
|
204
282
|
|
|
205
|
-
The
|
|
283
|
+
The method options object can contain request parameters supported by the generated HTTP client.
|
|
206
284
|
|
|
207
285
|
```ts
|
|
208
286
|
const result = await getSuppliers(
|
|
209
287
|
{ pageNumber: 1, pageSize: 25 },
|
|
210
|
-
undefined,
|
|
211
|
-
undefined,
|
|
212
288
|
{
|
|
213
|
-
|
|
214
|
-
|
|
289
|
+
params: {
|
|
290
|
+
headers: {
|
|
291
|
+
Authorization: `Bearer ${token}`,
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Request parameters can also be combined with callbacks.
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
const result = await getSuppliers(
|
|
302
|
+
{ pageNumber: 1, pageSize: 25 },
|
|
303
|
+
{
|
|
304
|
+
onError: handleError,
|
|
305
|
+
params: {
|
|
306
|
+
headers: {
|
|
307
|
+
Authorization: `Bearer ${token}`,
|
|
308
|
+
},
|
|
215
309
|
},
|
|
216
310
|
},
|
|
217
311
|
);
|
|
218
312
|
```
|
|
219
313
|
|
|
314
|
+
## Query methods without required filters
|
|
315
|
+
|
|
316
|
+
Some generated API methods require a query object at the raw generated client level, even when all query properties are optional.
|
|
317
|
+
|
|
318
|
+
The wrapper methods allow the query argument to be omitted. Internally, they pass an empty object to the raw generated method.
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
await exportPartners();
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
is handled like:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
await exportPartners({});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
When you want to pass options but no query, pass `undefined` as the first argument.
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
await exportPartners(undefined, {
|
|
334
|
+
onError: handleError,
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
220
338
|
## Filter-form generation
|
|
221
339
|
|
|
222
340
|
Set `typedApiUseFilterFormValues` to `true` to generate paginated methods that accept filter form values.
|
|
@@ -248,6 +366,19 @@ const filters: FilterFormValues<GetSuppliersQuery>[] = [
|
|
|
248
366
|
const result = await getSuppliers(filters, 1, 25, "name", "Ascending");
|
|
249
367
|
```
|
|
250
368
|
|
|
369
|
+
You can also pass method options as the final argument.
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
const result = await getSuppliers(filters, 1, 25, "name", "Ascending", {
|
|
373
|
+
onError: handleError,
|
|
374
|
+
params: {
|
|
375
|
+
headers: {
|
|
376
|
+
Authorization: `Bearer ${token}`,
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
```
|
|
381
|
+
|
|
251
382
|
Empty filter values are ignored by `buildQuery`.
|
|
252
383
|
|
|
253
384
|
## Multipart uploads
|
|
@@ -278,29 +409,30 @@ Arrays are appended as repeated fields, files keep their filename, primitives be
|
|
|
278
409
|
|
|
279
410
|
### Filter and sort types
|
|
280
411
|
|
|
281
|
-
| Export | Description
|
|
282
|
-
| -------------------------- |
|
|
283
|
-
| `FilterType` | Union of supported filter input types
|
|
284
|
-
| `OptionValue` | Option object with a display `name` and submitted `value`.
|
|
285
|
-
| `FilterFormValues<TQuery>` | Configuration object for one filter field mapped to a query property.
|
|
286
|
-
| `SortType` | UI sort state: Default, Neutral, Ascending, or Descending.
|
|
287
|
-
| `SortDirection` | Sort direction value accepted by generated query objects. Supports string or number values.
|
|
288
|
-
| `ApiSortDirection` | Sort direction values accepted by the generated API: Default, Ascending, or Descending.
|
|
289
|
-
| `sortTypes` | Constant list of all supported UI sort states.
|
|
412
|
+
| Export | Description |
|
|
413
|
+
| -------------------------- | ------------------------------------------------------------------------------------------- |
|
|
414
|
+
| `FilterType` | Union of supported filter input types used by generated filter-form methods. |
|
|
415
|
+
| `OptionValue` | Option object with a display `name` and submitted `value`. |
|
|
416
|
+
| `FilterFormValues<TQuery>` | Configuration object for one filter field mapped to a query property. |
|
|
417
|
+
| `SortType` | UI sort state: Default, Neutral, Ascending, or Descending. |
|
|
418
|
+
| `SortDirection` | Sort direction value accepted by generated query objects. Supports string or number values. |
|
|
419
|
+
| `ApiSortDirection` | Sort direction values accepted by the generated API: Default, Ascending, or Descending. |
|
|
420
|
+
| `sortTypes` | Constant list of all supported UI sort states. |
|
|
290
421
|
|
|
291
422
|
### Callback and method types
|
|
292
423
|
|
|
293
|
-
| Export
|
|
294
|
-
|
|
|
295
|
-
| `ApiSuccessHandler<TResponse>`
|
|
296
|
-
| `ApiErrorHandler<TResponse>`
|
|
297
|
-
| `ApiMethodCallbacks<TResponse>`
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
302
|
-
| `
|
|
303
|
-
| `
|
|
424
|
+
| Export | Description |
|
|
425
|
+
| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
426
|
+
| `ApiSuccessHandler<TResponse>` | Callback type for successful API results. |
|
|
427
|
+
| `ApiErrorHandler<TResponse>` | Callback type for failed API results. |
|
|
428
|
+
| `ApiMethodCallbacks<TResponse>` | Object shape containing optional `onSuccess`, `onError`, and `params` properties. |
|
|
429
|
+
| Generated method options, such as `GetSuppliersOptions` | Per-method options object generated for wrapper methods. Contains optional `onSuccess`, `onError`, and `params`. |
|
|
430
|
+
| `ExtractResponse<T>` | Extracts the response body type from a generated method promise. |
|
|
431
|
+
| `ExtractError<T>` | Extracts the error body type from a generated method promise. |
|
|
432
|
+
| `UnwrapArray<T>` | Extracts the item type from an array, otherwise keeps the original type. |
|
|
433
|
+
| `ExtractDataIfPaginated<T>` | Extracts the item type from a `{ data?: T[] }` paginated response. |
|
|
434
|
+
| `SortableKeys<T>` | Produces keys that can be used as sortable fields for a response type. |
|
|
435
|
+
| `WithoutRequestParams<T>` | Removes a trailing optional `RequestParams` argument from a generated method argument tuple. |
|
|
304
436
|
|
|
305
437
|
### HTTP types
|
|
306
438
|
|
|
@@ -311,16 +443,16 @@ Arrays are appended as repeated fields, files keep their filename, primitives be
|
|
|
311
443
|
|
|
312
444
|
### Utility functions
|
|
313
445
|
|
|
314
|
-
| Export | Description
|
|
315
|
-
| ---------------------------------- |
|
|
316
|
-
| `buildQuery<TQuery, TSortModel>()` | Builds a query object from filter form values, page values, and sort values.
|
|
317
|
-
| `extractArgsCallbacksAndParams()` |
|
|
318
|
-
| `extractArgsToastsAndParams()` | Backwards-compatible extractor for wrapper arguments with success/error handlers and request params.
|
|
319
|
-
| `handleApiResponse()` | Executes a generated API call and converts the response or thrown error into `ApiResult<T>`.
|
|
320
|
-
| `HandleApiResponseOptions<T>` | Options object for passing success and error callbacks to `handleApiResponse`.
|
|
321
|
-
| `getSortTypeFromSortDirection()` | Converts an API sort direction into a UI `SortType`.
|
|
322
|
-
| `getSortDirectionFromSortType()` | Converts a UI `SortType` into an API sort direction.
|
|
323
|
-
| `toFormData()` | Converts an object payload into `FormData`.
|
|
446
|
+
| Export | Description |
|
|
447
|
+
| ---------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
448
|
+
| `buildQuery<TQuery, TSortModel>()` | Builds a query object from filter form values, page values, and sort values. |
|
|
449
|
+
| `extractArgsCallbacksAndParams()` | Backwards-compatible helper for older generated files that used positional callbacks. |
|
|
450
|
+
| `extractArgsToastsAndParams()` | Backwards-compatible extractor for wrapper arguments with success/error handlers and request params. |
|
|
451
|
+
| `handleApiResponse()` | Executes a generated API call and converts the response or thrown error into `ApiResult<T>`. |
|
|
452
|
+
| `HandleApiResponseOptions<T>` | Options object for passing success and error callbacks to `handleApiResponse`. |
|
|
453
|
+
| `getSortTypeFromSortDirection()` | Converts an API sort direction into a UI `SortType`. |
|
|
454
|
+
| `getSortDirectionFromSortType()` | Converts a UI `SortType` into an API sort direction. |
|
|
455
|
+
| `toFormData()` | Converts an object payload into `FormData`. |
|
|
324
456
|
|
|
325
457
|
### Default callback functions
|
|
326
458
|
|
|
@@ -338,8 +470,6 @@ Additional README files are included in these folders:
|
|
|
338
470
|
| `src/interfaces/README.md` | Documents exported interfaces and result/filter/sort types. |
|
|
339
471
|
| `src/types/README.md` | Documents helper types used by generated wrapper methods. |
|
|
340
472
|
| `src/utils/README.md` | Documents runtime helper functions. |
|
|
341
|
-
| `scripts/README.md` | Documents the API generator script. |
|
|
342
|
-
| `bin/README.md` | Documents the command-line entry point. |
|
|
343
473
|
|
|
344
474
|
## Build the package
|
|
345
475
|
|
|
@@ -355,4 +485,6 @@ npm run generate:api
|
|
|
355
485
|
|
|
356
486
|
## Notes
|
|
357
487
|
|
|
358
|
-
Generated files inside `src/api` and `dist/api` depend on the Swagger document used during generation. Their exact method names
|
|
488
|
+
Generated files inside `src/api` and `dist/api` depend on the Swagger document used during generation. Their exact method names and model names will change when the OpenAPI document changes.
|
|
489
|
+
|
|
490
|
+
Generated route type files ending in `Route.ts` are removed from the generated output.
|
package/dist/index.d.cts
CHANGED
|
@@ -189,6 +189,17 @@ type ApiMethodCallbacks<TResponse> = {
|
|
|
189
189
|
params?: RequestParams;
|
|
190
190
|
};
|
|
191
191
|
|
|
192
|
+
type ApiMethodOptions<TMethodReturn, TRequestParams = RuntimeRequestParams> = {
|
|
193
|
+
onSuccess?: ApiSuccessHandler<ExtractResponse<TMethodReturn>>;
|
|
194
|
+
onError?: ApiErrorHandler<ExtractError<TMethodReturn>>;
|
|
195
|
+
params?: TRequestParams;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
type ApiMethodArguments<TMethod extends (...args: any[]) => unknown, TRequestParams = RuntimeRequestParams> = Parameters<TMethod> extends [
|
|
199
|
+
...infer Arguments,
|
|
200
|
+
TRequestParams?
|
|
201
|
+
] ? Arguments : Parameters<TMethod>;
|
|
202
|
+
|
|
192
203
|
/**
|
|
193
204
|
* Sort direction value accepted by generated query objects.
|
|
194
205
|
*
|
|
@@ -287,4 +298,4 @@ declare function getSortDirectionFromSortType(sortType: SortType | null | undefi
|
|
|
287
298
|
*/
|
|
288
299
|
declare function toFormData<T extends object>(payload: T): FormData;
|
|
289
300
|
|
|
290
|
-
export { type ApiErrorHandler, type ApiErrorResult, type ApiMethodCallbacks, type ApiResult, type ApiSortDirection, type ApiSuccessHandler, type ApiSuccessResult, type ExtractDataIfPaginated, type ExtractError, type ExtractResponse, type FilterFormValues, type FilterType, type HandleApiResponseOptions, type HttpResponse, type OptionValue, type RuntimeRequestParams, type SortDirection, type SortType, type SortableKeys, type UnwrapArray, type WithoutRequestParams, buildQuery, extractArgsCallbacksAndParams, extractArgsToastsAndParams, getSortDirectionFromSortType, getSortTypeFromSortDirection, handleApiResponse, sortTypes, toFormData };
|
|
301
|
+
export { type ApiErrorHandler, type ApiErrorResult, type ApiMethodArguments, type ApiMethodCallbacks, type ApiMethodOptions, type ApiResult, type ApiSortDirection, type ApiSuccessHandler, type ApiSuccessResult, type ExtractDataIfPaginated, type ExtractError, type ExtractResponse, type FilterFormValues, type FilterType, type HandleApiResponseOptions, type HttpResponse, type OptionValue, type RuntimeRequestParams, type SortDirection, type SortType, type SortableKeys, type UnwrapArray, type WithoutRequestParams, buildQuery, extractArgsCallbacksAndParams, extractArgsToastsAndParams, getSortDirectionFromSortType, getSortTypeFromSortDirection, handleApiResponse, sortTypes, toFormData };
|
package/dist/index.d.ts
CHANGED
|
@@ -189,6 +189,17 @@ type ApiMethodCallbacks<TResponse> = {
|
|
|
189
189
|
params?: RequestParams;
|
|
190
190
|
};
|
|
191
191
|
|
|
192
|
+
type ApiMethodOptions<TMethodReturn, TRequestParams = RuntimeRequestParams> = {
|
|
193
|
+
onSuccess?: ApiSuccessHandler<ExtractResponse<TMethodReturn>>;
|
|
194
|
+
onError?: ApiErrorHandler<ExtractError<TMethodReturn>>;
|
|
195
|
+
params?: TRequestParams;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
type ApiMethodArguments<TMethod extends (...args: any[]) => unknown, TRequestParams = RuntimeRequestParams> = Parameters<TMethod> extends [
|
|
199
|
+
...infer Arguments,
|
|
200
|
+
TRequestParams?
|
|
201
|
+
] ? Arguments : Parameters<TMethod>;
|
|
202
|
+
|
|
192
203
|
/**
|
|
193
204
|
* Sort direction value accepted by generated query objects.
|
|
194
205
|
*
|
|
@@ -287,4 +298,4 @@ declare function getSortDirectionFromSortType(sortType: SortType | null | undefi
|
|
|
287
298
|
*/
|
|
288
299
|
declare function toFormData<T extends object>(payload: T): FormData;
|
|
289
300
|
|
|
290
|
-
export { type ApiErrorHandler, type ApiErrorResult, type ApiMethodCallbacks, type ApiResult, type ApiSortDirection, type ApiSuccessHandler, type ApiSuccessResult, type ExtractDataIfPaginated, type ExtractError, type ExtractResponse, type FilterFormValues, type FilterType, type HandleApiResponseOptions, type HttpResponse, type OptionValue, type RuntimeRequestParams, type SortDirection, type SortType, type SortableKeys, type UnwrapArray, type WithoutRequestParams, buildQuery, extractArgsCallbacksAndParams, extractArgsToastsAndParams, getSortDirectionFromSortType, getSortTypeFromSortDirection, handleApiResponse, sortTypes, toFormData };
|
|
301
|
+
export { type ApiErrorHandler, type ApiErrorResult, type ApiMethodArguments, type ApiMethodCallbacks, type ApiMethodOptions, type ApiResult, type ApiSortDirection, type ApiSuccessHandler, type ApiSuccessResult, type ExtractDataIfPaginated, type ExtractError, type ExtractResponse, type FilterFormValues, type FilterType, type HandleApiResponseOptions, type HttpResponse, type OptionValue, type RuntimeRequestParams, type SortDirection, type SortType, type SortableKeys, type UnwrapArray, type WithoutRequestParams, buildQuery, extractArgsCallbacksAndParams, extractArgsToastsAndParams, getSortDirectionFromSortType, getSortTypeFromSortDirection, handleApiResponse, sortTypes, toFormData };
|
package/package.json
CHANGED
|
@@ -38,10 +38,11 @@ const swaggerFile =
|
|
|
38
38
|
const swaggerUrl =
|
|
39
39
|
process.env.SWAGGER_URL ??
|
|
40
40
|
process.env.npm_config_swagger_url ??
|
|
41
|
-
config.swaggerUrl
|
|
42
|
-
"https://localhost:7000/swagger/v1/swagger.json";
|
|
41
|
+
config.swaggerUrl;
|
|
43
42
|
|
|
44
|
-
const swaggerInput = swaggerFile
|
|
43
|
+
const swaggerInput = swaggerFile
|
|
44
|
+
? path.resolve(cwd, swaggerFile)
|
|
45
|
+
: (swaggerUrl ?? path.resolve(cwd, "swagger/swagger.json"));
|
|
45
46
|
|
|
46
47
|
const apiRoot = path.resolve(
|
|
47
48
|
cwd,
|
|
@@ -50,6 +51,7 @@ const apiRoot = path.resolve(
|
|
|
50
51
|
config.apiOutput ??
|
|
51
52
|
"src/api",
|
|
52
53
|
);
|
|
54
|
+
|
|
53
55
|
const generatedDir = path.join(apiRoot, "generated");
|
|
54
56
|
const methodsDir = path.join(apiRoot, "methods");
|
|
55
57
|
|
|
@@ -157,6 +159,7 @@ async function generateOpenApiClient() {
|
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
await generateApi(generateOptions);
|
|
162
|
+
|
|
160
163
|
removeGeneratedRouteFiles();
|
|
161
164
|
}
|
|
162
165
|
|
|
@@ -226,7 +229,6 @@ ${createImportStatement({
|
|
|
226
229
|
typeOnly: true,
|
|
227
230
|
})}
|
|
228
231
|
|
|
229
|
-
|
|
230
232
|
export function ${defaultSuccessHandlerName}<T>(
|
|
231
233
|
_response: ApiSuccessResult<T>,
|
|
232
234
|
): void | Promise<void> {
|
|
@@ -374,102 +376,97 @@ function getAllTsFiles(dir) {
|
|
|
374
376
|
return results;
|
|
375
377
|
}
|
|
376
378
|
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
console.log(
|
|
382
|
-
`Checking ${tsFiles.length} generated TypeScript files for multipart methods...`,
|
|
383
|
-
);
|
|
379
|
+
function getGeneratedMethods(source) {
|
|
380
|
+
const methodRegex = /^\s*(\w+)\s*=\s*\(/gm;
|
|
381
|
+
const matches = [...source.matchAll(methodRegex)];
|
|
384
382
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
continue;
|
|
391
|
-
}
|
|
383
|
+
return matches.map((match, index) => {
|
|
384
|
+
const methodName = match[1];
|
|
385
|
+
const startIndex = match.index ?? 0;
|
|
386
|
+
const endIndex =
|
|
387
|
+
index + 1 < matches.length ? matches[index + 1].index : source.length;
|
|
392
388
|
|
|
393
|
-
const
|
|
389
|
+
const methodSource = source.slice(startIndex, endIndex);
|
|
394
390
|
|
|
395
|
-
|
|
396
|
-
|
|
391
|
+
return {
|
|
392
|
+
methodName,
|
|
393
|
+
methodSource,
|
|
394
|
+
isFormData: methodSource.includes("type: ContentType.FormData"),
|
|
395
|
+
};
|
|
396
|
+
});
|
|
397
|
+
}
|
|
397
398
|
|
|
398
|
-
|
|
399
|
+
function splitTopLevelArguments(value) {
|
|
400
|
+
const args = [];
|
|
401
|
+
let current = "";
|
|
402
|
+
let depth = 0;
|
|
403
|
+
let quote = "";
|
|
399
404
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
console.log(
|
|
404
|
-
` Replacing multipart payload type "${currentType.trim()}" with FormData`,
|
|
405
|
-
);
|
|
405
|
+
for (let index = 0; index < value.length; index++) {
|
|
406
|
+
const char = value[index];
|
|
407
|
+
const previousChar = value[index - 1];
|
|
406
408
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
+
if (quote) {
|
|
410
|
+
current += char;
|
|
409
411
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
412
|
+
if (char === quote && previousChar !== "\\") {
|
|
413
|
+
quote = "";
|
|
414
|
+
}
|
|
413
415
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
416
418
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
)}`,
|
|
422
|
-
);
|
|
419
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
420
|
+
quote = char;
|
|
421
|
+
current += char;
|
|
422
|
+
continue;
|
|
423
423
|
}
|
|
424
|
-
}
|
|
425
424
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
425
|
+
if (char === "(" || char === "{" || char === "[" || char === "<") {
|
|
426
|
+
depth++;
|
|
427
|
+
current += char;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
431
430
|
|
|
432
|
-
|
|
433
|
-
|
|
431
|
+
if (char === ")" || char === "}" || char === "]" || char === ">") {
|
|
432
|
+
depth--;
|
|
433
|
+
current += char;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
434
436
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
+
if (char === "," && depth === 0) {
|
|
438
|
+
if (current.trim()) {
|
|
439
|
+
args.push(current.trim());
|
|
440
|
+
}
|
|
437
441
|
|
|
438
|
-
|
|
442
|
+
current = "";
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
439
445
|
|
|
440
|
-
|
|
441
|
-
return false;
|
|
446
|
+
current += char;
|
|
442
447
|
}
|
|
443
448
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const nextMatch = nextMethodPattern.exec(source);
|
|
448
|
-
const endIndex = nextMatch?.index ?? source.length;
|
|
449
|
-
|
|
450
|
-
const methodSource = source.slice(startMatch.index, endIndex);
|
|
449
|
+
if (current.trim()) {
|
|
450
|
+
args.push(current.trim());
|
|
451
|
+
}
|
|
451
452
|
|
|
452
|
-
return
|
|
453
|
+
return args;
|
|
453
454
|
}
|
|
454
455
|
|
|
455
|
-
function
|
|
456
|
-
const
|
|
457
|
-
const matches = [...source.matchAll(methodRegex)];
|
|
456
|
+
function getGeneratedMethodArgumentCount(signatureParams) {
|
|
457
|
+
const args = splitTopLevelArguments(signatureParams);
|
|
458
458
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const endIndex =
|
|
463
|
-
index + 1 < matches.length ? matches[index + 1].index : source.length;
|
|
459
|
+
if (args.length === 0) {
|
|
460
|
+
return 0;
|
|
461
|
+
}
|
|
464
462
|
|
|
465
|
-
|
|
463
|
+
const lastArg = args[args.length - 1];
|
|
466
464
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
});
|
|
465
|
+
if (/\bparams\s*:\s*RequestParams\b/.test(lastArg)) {
|
|
466
|
+
return args.length - 1;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return args.length;
|
|
473
470
|
}
|
|
474
471
|
|
|
475
472
|
async function createMethodFiles() {
|
|
@@ -518,9 +515,9 @@ async function createMethodFiles() {
|
|
|
518
515
|
}
|
|
519
516
|
|
|
520
517
|
const params = signatureMatch[1].trim();
|
|
518
|
+
const methodArgumentCount = getGeneratedMethodArgumentCount(params);
|
|
521
519
|
|
|
522
520
|
const returnTypeMatch = methodSource.match(/this\.request<([^,>]+)/m);
|
|
523
|
-
|
|
524
521
|
const returnType = returnTypeMatch?.[1] ?? "";
|
|
525
522
|
|
|
526
523
|
const isPaginated =
|
|
@@ -540,6 +537,7 @@ async function createMethodFiles() {
|
|
|
540
537
|
nonQueryMethods.push({
|
|
541
538
|
methodName,
|
|
542
539
|
isFormData,
|
|
540
|
+
methodArgumentCount,
|
|
543
541
|
});
|
|
544
542
|
}
|
|
545
543
|
|
|
@@ -556,8 +554,6 @@ export type ${toQueryName(methodName)} =
|
|
|
556
554
|
|
|
557
555
|
const hasPaginatedMethods = paginatedMethods.length > 0;
|
|
558
556
|
|
|
559
|
-
const hasNonQueryMethods = nonQueryMethods.length > 0;
|
|
560
|
-
|
|
561
557
|
const hasFormDataMethods = nonQueryMethods.some(
|
|
562
558
|
({ isFormData }) => isFormData,
|
|
563
559
|
);
|
|
@@ -578,14 +574,13 @@ export async function ${methodName}(
|
|
|
578
574
|
ExtractResponse<ReturnType<${className}["${methodName}"]>>
|
|
579
575
|
> | null = null,
|
|
580
576
|
sortDirection?: SortDirection,
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
ExtractError<ReturnType<${className}["${methodName}"]>>
|
|
586
|
-
>,
|
|
587
|
-
params?: RequestParams
|
|
577
|
+
options: ApiMethodOptions<
|
|
578
|
+
ReturnType<${className}["${methodName}"]>,
|
|
579
|
+
RequestParams
|
|
580
|
+
> = {}
|
|
588
581
|
): Promise<ApiResult<ExtractResponse<ReturnType<${className}["${methodName}"]>>>> {
|
|
582
|
+
const { onSuccess, onError, params } = options;
|
|
583
|
+
|
|
589
584
|
return handleApiResponse(
|
|
590
585
|
() =>
|
|
591
586
|
${instanceName}.${methodName}(
|
|
@@ -608,14 +603,13 @@ export async function ${methodName}(
|
|
|
608
603
|
return `
|
|
609
604
|
export async function ${methodName}(
|
|
610
605
|
query?: ${toQueryName(methodName)},
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
ExtractError<ReturnType<${className}["${methodName}"]>>
|
|
616
|
-
>,
|
|
617
|
-
params?: RequestParams
|
|
606
|
+
options: ApiMethodOptions<
|
|
607
|
+
ReturnType<${className}["${methodName}"]>,
|
|
608
|
+
RequestParams
|
|
609
|
+
> = {}
|
|
618
610
|
): Promise<ApiResult<ExtractResponse<ReturnType<${className}["${methodName}"]>>>> {
|
|
611
|
+
const { onSuccess, onError, params } = options;
|
|
612
|
+
|
|
619
613
|
return handleApiResponse(
|
|
620
614
|
() =>
|
|
621
615
|
${instanceName}.${methodName}(
|
|
@@ -634,13 +628,10 @@ export async function ${methodName}(
|
|
|
634
628
|
`
|
|
635
629
|
export async function ${methodName}(
|
|
636
630
|
query?: ${toQueryName(methodName)},
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
ExtractError<ReturnType<${className}["${methodName}"]>>
|
|
642
|
-
>,
|
|
643
|
-
params?: RequestParams
|
|
631
|
+
options: ApiMethodOptions<
|
|
632
|
+
ReturnType<${className}["${methodName}"]>,
|
|
633
|
+
RequestParams
|
|
634
|
+
> = {}
|
|
644
635
|
): Promise<
|
|
645
636
|
ApiResult<
|
|
646
637
|
ExtractResponse<
|
|
@@ -650,6 +641,8 @@ export async function ${methodName}(
|
|
|
650
641
|
>
|
|
651
642
|
>
|
|
652
643
|
> {
|
|
644
|
+
const { onSuccess, onError, params } = options;
|
|
645
|
+
|
|
653
646
|
return handleApiResponse(
|
|
654
647
|
() =>
|
|
655
648
|
${instanceName}.${methodName}(
|
|
@@ -664,20 +657,17 @@ export async function ${methodName}(
|
|
|
664
657
|
.join("\n\n");
|
|
665
658
|
|
|
666
659
|
const nonQueryMethodWrappers = nonQueryMethods
|
|
667
|
-
.map(({ methodName, isFormData }) => {
|
|
660
|
+
.map(({ methodName, isFormData, methodArgumentCount }) => {
|
|
668
661
|
if (isFormData) {
|
|
669
662
|
return `
|
|
670
663
|
export async function ${methodName}(
|
|
671
664
|
data: Parameters<
|
|
672
665
|
${className}["${methodName}"]
|
|
673
666
|
>[0],
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
ExtractError<ReturnType<${className}["${methodName}"]>>
|
|
679
|
-
>,
|
|
680
|
-
params?: RequestParams
|
|
667
|
+
options: ApiMethodOptions<
|
|
668
|
+
ReturnType<${className}["${methodName}"]>,
|
|
669
|
+
RequestParams
|
|
670
|
+
> = {}
|
|
681
671
|
): Promise<
|
|
682
672
|
ApiResult<
|
|
683
673
|
ExtractResponse<
|
|
@@ -687,6 +677,7 @@ export async function ${methodName}(
|
|
|
687
677
|
>
|
|
688
678
|
>
|
|
689
679
|
> {
|
|
680
|
+
const { onSuccess, onError, params } = options;
|
|
690
681
|
const formData = toFormData(data);
|
|
691
682
|
|
|
692
683
|
return handleApiResponse(
|
|
@@ -705,25 +696,15 @@ export async function ${methodName}(
|
|
|
705
696
|
|
|
706
697
|
return `
|
|
707
698
|
export async function ${methodName}(
|
|
708
|
-
...
|
|
699
|
+
...argsWithOptions: [
|
|
709
700
|
...ApiMethodArguments<
|
|
710
|
-
${className}["${methodName}"]
|
|
701
|
+
${className}["${methodName}"],
|
|
702
|
+
RequestParams
|
|
711
703
|
>,
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
>
|
|
717
|
-
>
|
|
718
|
-
>?,
|
|
719
|
-
ApiErrorHandler<
|
|
720
|
-
ExtractError<
|
|
721
|
-
ReturnType<
|
|
722
|
-
${className}["${methodName}"]
|
|
723
|
-
>
|
|
724
|
-
>
|
|
725
|
-
>?,
|
|
726
|
-
RequestParams?
|
|
704
|
+
ApiMethodOptions<
|
|
705
|
+
ReturnType<${className}["${methodName}"]>,
|
|
706
|
+
RequestParams
|
|
707
|
+
>?
|
|
727
708
|
]
|
|
728
709
|
): Promise<
|
|
729
710
|
ApiResult<
|
|
@@ -734,26 +715,17 @@ export async function ${methodName}(
|
|
|
734
715
|
>
|
|
735
716
|
>
|
|
736
717
|
> {
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
${className}["${methodName}"]
|
|
749
|
-
>
|
|
750
|
-
>,
|
|
751
|
-
ExtractError<
|
|
752
|
-
ReturnType<
|
|
753
|
-
${className}["${methodName}"]
|
|
754
|
-
>
|
|
755
|
-
>
|
|
756
|
-
>(argsWithCallbacks);
|
|
718
|
+
const args = [...argsWithOptions] as unknown[];
|
|
719
|
+
|
|
720
|
+
const options =
|
|
721
|
+
args.length > ${methodArgumentCount}
|
|
722
|
+
? (args.pop() as ApiMethodOptions<
|
|
723
|
+
ReturnType<${className}["${methodName}"]>,
|
|
724
|
+
RequestParams
|
|
725
|
+
>)
|
|
726
|
+
: {};
|
|
727
|
+
|
|
728
|
+
const { onSuccess, onError, params } = options ?? {};
|
|
757
729
|
|
|
758
730
|
const requestArgs = [
|
|
759
731
|
...args,
|
|
@@ -776,16 +748,15 @@ export async function ${methodName}(
|
|
|
776
748
|
|
|
777
749
|
const runtimeValueImportNames = [
|
|
778
750
|
...(hasPaginatedMethods && useFilterFormValues ? ["buildQuery"] : []),
|
|
779
|
-
...(hasRegularNonQueryMethods ? ["extractArgsCallbacksAndParams"] : []),
|
|
780
751
|
...(hasFormDataMethods ? ["toFormData"] : []),
|
|
781
752
|
"handleApiResponse",
|
|
782
753
|
];
|
|
754
|
+
|
|
783
755
|
const runtimeTypeImportNames = [
|
|
784
756
|
"ApiResult",
|
|
785
|
-
"
|
|
786
|
-
"
|
|
757
|
+
"ApiMethodOptions",
|
|
758
|
+
...(hasRegularNonQueryMethods ? ["ApiMethodArguments"] : []),
|
|
787
759
|
"ExtractResponse",
|
|
788
|
-
"ExtractError",
|
|
789
760
|
|
|
790
761
|
...(hasPaginatedMethods && useFilterFormValues
|
|
791
762
|
? [
|
|
@@ -839,20 +810,6 @@ export async function ${methodName}(
|
|
|
839
810
|
})
|
|
840
811
|
: "";
|
|
841
812
|
|
|
842
|
-
const apiMethodArgumentsType = hasRegularNonQueryMethods
|
|
843
|
-
? `
|
|
844
|
-
type ApiMethodArguments<
|
|
845
|
-
TMethod extends (...args: any[]) => unknown
|
|
846
|
-
> =
|
|
847
|
-
Parameters<TMethod> extends [
|
|
848
|
-
...infer Arguments,
|
|
849
|
-
unknown?
|
|
850
|
-
]
|
|
851
|
-
? Arguments
|
|
852
|
-
: Parameters<TMethod>;
|
|
853
|
-
`.trim()
|
|
854
|
-
: "";
|
|
855
|
-
|
|
856
813
|
const content = `
|
|
857
814
|
${runtimeValueImports}
|
|
858
815
|
|
|
@@ -864,8 +821,6 @@ ${generatedValueImports}
|
|
|
864
821
|
|
|
865
822
|
${generatedTypeImports}
|
|
866
823
|
|
|
867
|
-
${apiMethodArgumentsType}
|
|
868
|
-
|
|
869
824
|
/* =======================
|
|
870
825
|
Query Types
|
|
871
826
|
======================= */
|