typedapi-client-helpers 0.1.5 → 0.1.7

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.
Files changed (129) hide show
  1. package/README.md +314 -676
  2. package/dist/api/generated/Import.d.ts +22 -0
  3. package/dist/api/generated/Import.d.ts.map +1 -0
  4. package/dist/api/generated/Import.js +48 -0
  5. package/dist/api/generated/Import.js.map +1 -0
  6. package/dist/api/generated/ImportRoute.d.ts +30 -0
  7. package/dist/api/generated/ImportRoute.d.ts.map +1 -0
  8. package/dist/api/generated/ImportRoute.js +13 -0
  9. package/dist/api/generated/ImportRoute.js.map +1 -0
  10. package/dist/api/generated/Order.d.ts +38 -0
  11. package/dist/api/generated/Order.d.ts.map +1 -0
  12. package/dist/api/generated/Order.js +75 -0
  13. package/dist/api/generated/Order.js.map +1 -0
  14. package/dist/api/generated/OrderRoute.d.ts +83 -0
  15. package/dist/api/generated/OrderRoute.d.ts.map +1 -0
  16. package/dist/api/generated/OrderRoute.js +13 -0
  17. package/dist/api/generated/OrderRoute.js.map +1 -0
  18. package/dist/api/generated/Product.d.ts +62 -0
  19. package/dist/api/generated/Product.d.ts.map +1 -0
  20. package/dist/api/generated/Product.js +114 -0
  21. package/dist/api/generated/Product.js.map +1 -0
  22. package/dist/api/generated/ProductRoute.d.ts +140 -0
  23. package/dist/api/generated/ProductRoute.d.ts.map +1 -0
  24. package/dist/api/generated/ProductRoute.js +13 -0
  25. package/dist/api/generated/ProductRoute.js.map +1 -0
  26. package/dist/api/generated/Report.d.ts +14 -0
  27. package/dist/api/generated/Report.d.ts.map +1 -0
  28. package/dist/api/generated/Report.js +32 -0
  29. package/dist/api/generated/Report.js.map +1 -0
  30. package/dist/api/generated/ReportRoute.d.ts +23 -0
  31. package/dist/api/generated/ReportRoute.d.ts.map +1 -0
  32. package/dist/api/generated/ReportRoute.js +13 -0
  33. package/dist/api/generated/ReportRoute.js.map +1 -0
  34. package/dist/api/generated/Supplier.d.ts +46 -0
  35. package/dist/api/generated/Supplier.d.ts.map +1 -0
  36. package/dist/api/generated/Supplier.js +87 -0
  37. package/dist/api/generated/Supplier.js.map +1 -0
  38. package/dist/api/generated/SupplierRoute.d.ts +101 -0
  39. package/dist/api/generated/SupplierRoute.d.ts.map +1 -0
  40. package/dist/api/generated/SupplierRoute.js +13 -0
  41. package/dist/api/generated/SupplierRoute.js.map +1 -0
  42. package/dist/api/generated/data-contracts.d.ts +277 -0
  43. package/dist/api/generated/data-contracts.d.ts.map +1 -0
  44. package/dist/api/generated/data-contracts.js +26 -0
  45. package/dist/api/generated/data-contracts.js.map +1 -0
  46. package/dist/api/generated/http-client.d.ts +61 -0
  47. package/dist/api/generated/http-client.d.ts.map +1 -0
  48. package/dist/api/generated/http-client.js +171 -0
  49. package/dist/api/generated/http-client.js.map +1 -0
  50. package/dist/api/index.d.ts +8 -0
  51. package/dist/api/index.d.ts.map +1 -0
  52. package/dist/api/index.js +8 -0
  53. package/dist/api/index.js.map +1 -0
  54. package/dist/api/methods/Import.api.d.ts +6 -0
  55. package/dist/api/methods/Import.api.d.ts.map +1 -0
  56. package/dist/api/methods/Import.api.js +27 -0
  57. package/dist/api/methods/Import.api.js.map +1 -0
  58. package/dist/api/methods/Order.api.d.ts +29 -0
  59. package/dist/api/methods/Order.api.d.ts.map +1 -0
  60. package/dist/api/methods/Order.api.js +52 -0
  61. package/dist/api/methods/Order.api.js.map +1 -0
  62. package/dist/api/methods/Product.api.d.ts +39 -0
  63. package/dist/api/methods/Product.api.d.ts.map +1 -0
  64. package/dist/api/methods/Product.api.js +69 -0
  65. package/dist/api/methods/Product.api.js.map +1 -0
  66. package/dist/api/methods/Report.api.d.ts +6 -0
  67. package/dist/api/methods/Report.api.d.ts.map +1 -0
  68. package/dist/api/methods/Report.api.js +19 -0
  69. package/dist/api/methods/Report.api.js.map +1 -0
  70. package/dist/api/methods/Supplier.api.d.ts +35 -0
  71. package/dist/api/methods/Supplier.api.d.ts.map +1 -0
  72. package/dist/api/methods/Supplier.api.js +63 -0
  73. package/dist/api/methods/Supplier.api.js.map +1 -0
  74. package/dist/index.cjs +47 -551
  75. package/dist/index.d.cts +108 -18
  76. package/dist/index.d.ts +108 -18
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +46 -551
  79. package/dist/index.js.map +1 -0
  80. package/dist/interfaces/ApiResult.d.ts +17 -0
  81. package/dist/interfaces/ApiResult.d.ts.map +1 -0
  82. package/dist/interfaces/ApiResult.js +2 -0
  83. package/dist/interfaces/ApiResult.js.map +1 -0
  84. package/dist/interfaces/Filter.d.ts +31 -0
  85. package/dist/interfaces/Filter.d.ts.map +1 -0
  86. package/dist/interfaces/Filter.js +2 -0
  87. package/dist/interfaces/Filter.js.map +1 -0
  88. package/dist/interfaces/SortType.d.ts +7 -0
  89. package/dist/interfaces/SortType.d.ts.map +1 -0
  90. package/dist/interfaces/SortType.js +2 -0
  91. package/dist/interfaces/SortType.js.map +1 -0
  92. package/dist/types/ApiCallOptions.d.ts +9 -0
  93. package/dist/types/ApiCallOptions.d.ts.map +1 -0
  94. package/dist/types/ApiCallOptions.js +2 -0
  95. package/dist/types/ApiCallOptions.js.map +1 -0
  96. package/dist/types/ApiMethodTypes.d.ts +24 -0
  97. package/dist/types/ApiMethodTypes.d.ts.map +1 -0
  98. package/dist/types/ApiMethodTypes.js +2 -0
  99. package/dist/types/ApiMethodTypes.js.map +1 -0
  100. package/dist/types/HttpResponse.d.ts +16 -0
  101. package/dist/types/HttpResponse.d.ts.map +1 -0
  102. package/dist/types/HttpResponse.js +2 -0
  103. package/dist/types/HttpResponse.js.map +1 -0
  104. package/dist/utils/SortTypeFromSortDirection.d.ts +22 -0
  105. package/dist/utils/SortTypeFromSortDirection.d.ts.map +1 -0
  106. package/dist/utils/SortTypeFromSortDirection.js +45 -0
  107. package/dist/utils/SortTypeFromSortDirection.js.map +1 -0
  108. package/dist/utils/buildQuery.d.ts +11 -0
  109. package/dist/utils/buildQuery.d.ts.map +1 -0
  110. package/dist/utils/buildQuery.js +94 -0
  111. package/dist/utils/buildQuery.js.map +1 -0
  112. package/dist/utils/extractArgsCallbacksAndParams.d.ts +22 -0
  113. package/dist/utils/extractArgsCallbacksAndParams.d.ts.map +1 -0
  114. package/dist/utils/extractArgsCallbacksAndParams.js +44 -0
  115. package/dist/utils/extractArgsCallbacksAndParams.js.map +1 -0
  116. package/dist/utils/extractArgsToastsAndParams.d.ts +18 -0
  117. package/dist/utils/extractArgsToastsAndParams.d.ts.map +1 -0
  118. package/dist/utils/extractArgsToastsAndParams.js +40 -0
  119. package/dist/utils/extractArgsToastsAndParams.js.map +1 -0
  120. package/dist/utils/handleApiResponse.d.ts +9 -0
  121. package/dist/utils/handleApiResponse.d.ts.map +1 -0
  122. package/dist/utils/handleApiResponse.js +49 -0
  123. package/dist/utils/handleApiResponse.js.map +1 -0
  124. package/dist/utils/toFormData.d.ts +8 -0
  125. package/dist/utils/toFormData.d.ts.map +1 -0
  126. package/dist/utils/toFormData.js +68 -0
  127. package/dist/utils/toFormData.js.map +1 -0
  128. package/package.json +11 -3
  129. package/scripts/generate-api-minimal.mjs +263 -25
package/README.md CHANGED
@@ -1,676 +1,314 @@
1
- # typedapi-client-helpers
2
-
3
- Generate a typed TypeScript API client from an OpenAPI/Swagger document and use reusable helpers for API responses, filtering, sorting, pagination, callbacks, and multipart form data.
4
-
5
- The generated client uses the native `fetch` API and is created inside your own project, so the generated models and methods remain available for inspection and customization.
6
-
7
- ## Features
8
-
9
- * Generates TypeScript models and API methods from OpenAPI
10
- * Uses the native `fetch` API
11
- * Generates methods grouped by OpenAPI tags
12
- * Creates typed wrapper methods around generated requests
13
- * Returns a consistent `ApiResult<T>`
14
- * Supports success and error callbacks
15
- * Supports custom request parameters and headers
16
- * Supports query parameters, pagination, filtering, and sorting
17
- * Converts upload payloads to `FormData`
18
- * Supports local Swagger files and remote Swagger URLs
19
- * Supports type-only imports
20
- * Works with TypeScript frontend projects such as React, Angular, and Vue
21
-
22
- ## Installation
23
-
24
- ```bash
25
- npm install typedapi-client-helpers
26
- ```
27
-
28
- ## Add the generator command
29
-
30
- Add the following script to your project's `package.json`:
31
-
32
- ```json
33
- {
34
- "scripts": {
35
- "generate:api": "typedapi-generate"
36
- }
37
- }
38
- ```
39
-
40
- You can then generate the API client with:
41
-
42
- ```bash
43
- npm run generate:api
44
- ```
45
-
46
- ## Configuration
47
-
48
- The generator can be configured through the `config` property in your project's `package.json`.
49
-
50
- ### Generate from a Swagger URL
51
-
52
- ```json
53
- {
54
- "scripts": {
55
- "generate:api": "typedapi-generate"
56
- },
57
- "config": {
58
- "swaggerUrl": "https://localhost:7000/swagger/v1/swagger.json",
59
- "apiOutput": "src/api",
60
- "typedApiUseTypeOnlyImports": true,
61
- "typedApiUseFilterFormValues": false
62
- }
63
- }
64
- ```
65
-
66
- ### Generate from a local Swagger file
67
-
68
- ```json
69
- {
70
- "scripts": {
71
- "generate:api": "typedapi-generate"
72
- },
73
- "config": {
74
- "swaggerFile": "swagger/openapi.json",
75
- "apiOutput": "src/api",
76
- "typedApiUseTypeOnlyImports": true,
77
- "typedApiUseFilterFormValues": false
78
- }
79
- }
80
- ```
81
-
82
- When `swaggerFile` is configured, it takes precedence over `swaggerUrl`.
83
-
84
- ## Configuration options
85
-
86
- | Option | Default | Description |
87
- | ----------------------------- | ------------------------------------------------ | -------------------------------------------------------- |
88
- | `swaggerUrl` | `https://localhost:7000/swagger/v1/swagger.json` | URL of the OpenAPI document |
89
- | `swaggerFile` | — | Path to a local OpenAPI document |
90
- | `apiOutput` | `src/api` | Directory where the generated API is written |
91
- | `typedApiUseTypeOnlyImports` | `false` | Generates `import type` statements for type-only imports |
92
- | `typedApiUseFilterFormValues` | `false` | Generates filter-form arguments for paginated methods |
93
-
94
- ## Environment variables
95
-
96
- Configuration can also be supplied through environment variables.
97
-
98
- | Environment variable | Description |
99
- | ---------------------------------- | -------------------------------------------------------- |
100
- | `SWAGGER_URL` | URL of the OpenAPI document |
101
- | `SWAGGER_FILE` | Path to a local OpenAPI document |
102
- | `API_OUTPUT` | Generated API output directory |
103
- | `TYPED_API_USE_TYPE_ONLY_IMPORTS` | Enables type-only imports when set to `true` |
104
- | `TYPED_API_USE_FILTER_FORM_VALUES` | Enables filter-form method generation when set to `true` |
105
-
106
- Example:
107
-
108
- ```bash
109
- SWAGGER_URL=https://localhost:7000/swagger/v1/swagger.json npm run generate:api
110
- ```
111
-
112
- Command-line npm configuration is also supported:
113
-
114
- ```bash
115
- npm run generate:api --swagger-url=https://localhost:7000/swagger/v1/swagger.json
116
- ```
117
-
118
- ```bash
119
- npm run generate:api --swagger-file=swagger/openapi.json
120
- ```
121
-
122
- ```bash
123
- npm run generate:api --api-output=src/api
124
- ```
125
-
126
- ## Generated structure
127
-
128
- Running the generator creates an API directory similar to:
129
-
130
- ```text
131
- src/
132
- └── api/
133
- ├── generated/
134
- │ ├── data-contracts.ts
135
- │ ├── http-client.ts
136
- │ ├── Product.ts
137
- │ ├── ProductRoute.ts
138
- │ ├── Supplier.ts
139
- │ └── SupplierRoute.ts
140
- ├── methods/
141
- │ ├── Product.api.ts
142
- │ └── Supplier.api.ts
143
- └── index.ts
144
- ```
145
-
146
- The `generated` directory contains the client produced from the OpenAPI document.
147
-
148
- The `methods` directory contains typed wrapper functions that:
149
-
150
- * Handle successful and failed responses
151
- * Return `ApiResult<T>`
152
- * Support success and error callbacks
153
- * Accept custom request parameters
154
- * Convert multipart request objects to `FormData`
155
-
156
- ## Export the generated API
157
-
158
- Create or update `src/api/index.ts` so consumers can import the generated types and methods from one location:
159
-
160
- ```ts
161
- export * from "./generated/data-contracts";
162
- export * from "./generated/http-client";
163
-
164
- export * from "./methods/Product.api";
165
- export * from "./methods/Supplier.api";
166
- ```
167
-
168
- The exact method files depend on the tags in your OpenAPI document.
169
-
170
- ## Calling generated methods
171
-
172
- Generated wrapper methods return a typed `ApiResult<T>`.
173
-
174
- ```ts
175
- import { getSuppliers } from "./api";
176
-
177
- const result = await getSuppliers({
178
- pageNumber: 1,
179
- pageSize: 25,
180
- });
181
-
182
- if (result.ok) {
183
- console.log(result.response);
184
- } else {
185
- console.error(result.status, result.error);
186
- }
187
- ```
188
-
189
- `ApiResult<T>` is a discriminated union:
190
-
191
- ```ts
192
- type ApiResult<T> =
193
- | {
194
- ok: true;
195
- status: number;
196
- response: T;
197
- }
198
- | {
199
- ok: false;
200
- status: number;
201
- response?: T;
202
- error: unknown;
203
- };
204
- ```
205
-
206
- Checking `result.ok` automatically narrows the result to either the successful or failed response type.
207
-
208
- ## Success and error callbacks
209
-
210
- Generated methods support optional success and error callbacks.
211
-
212
- ```ts
213
- import { getSuppliers } from "./api";
214
-
215
- const result = await getSuppliers(
216
- {
217
- pageNumber: 1,
218
- pageSize: 25,
219
- },
220
- async (response) => {
221
- console.log("Suppliers loaded:", response);
222
- },
223
- async (error) => {
224
- console.error("Unable to load suppliers:", error);
225
- },
226
- );
227
- ```
228
-
229
- The method still returns an `ApiResult<T>`, even when callbacks are provided.
230
-
231
- ## Create and update requests
232
-
233
- Body-based API methods keep the argument types generated from the OpenAPI document.
234
-
235
- ```ts
236
- import { createSupplier } from "./api";
237
-
238
- const result = await createSupplier({
239
- id: "supplier-1",
240
- name: "Example Supplier",
241
- active: true,
242
- countryCode: "NL",
243
- email: "supplier@example.com",
244
- rating: 4.5,
245
- });
246
-
247
- if (!result.ok) {
248
- console.error("Supplier creation failed:", result.error);
249
- }
250
- ```
251
-
252
- Callbacks can be added after the generated API arguments:
253
-
254
- ```ts
255
- await createSupplier(
256
- {
257
- id: "supplier-1",
258
- name: "Example Supplier",
259
- active: true,
260
- countryCode: "NL",
261
- email: "supplier@example.com",
262
- rating: 4.5,
263
- },
264
- (supplier) => {
265
- console.log("Created supplier:", supplier);
266
- },
267
- (error) => {
268
- console.error("Creation failed:", error);
269
- },
270
- );
271
- ```
272
-
273
- ## Custom request parameters
274
-
275
- The final argument of a generated wrapper method can contain request configuration supported by the generated HTTP client.
276
-
277
- For example, custom headers can be supplied as follows:
278
-
279
- ```ts
280
- import { getSuppliers } from "./api";
281
-
282
- const result = await getSuppliers(
283
- {
284
- pageNumber: 1,
285
- pageSize: 25,
286
- },
287
- undefined,
288
- undefined,
289
- {
290
- headers: {
291
- Authorization: `Bearer ${token}`,
292
- },
293
- },
294
- );
295
- ```
296
-
297
- ## Filter-form generation
298
-
299
- Set `typedApiUseFilterFormValues` to `true` to generate paginated methods that accept filter-form values rather than a query object.
300
-
301
- ```json
302
- {
303
- "config": {
304
- "swaggerUrl": "https://localhost:7000/swagger/v1/swagger.json",
305
- "apiOutput": "src/api",
306
- "typedApiUseFilterFormValues": true
307
- }
308
- }
309
- ```
310
-
311
- A generated paginated method can then be called with filters, pagination, and sorting:
312
-
313
- ```ts
314
- import type { FilterFormValues } from "typedapi-client-helpers";
315
- import {
316
- getSuppliers,
317
- type GetSuppliersQuery,
318
- } from "./api";
319
-
320
- const filters: FilterFormValues<GetSuppliersQuery>[] = [
321
- {
322
- name: "Supplier name",
323
- filterName: "name",
324
- type: "string",
325
- value: "Example",
326
- isAList: false,
327
- },
328
- {
329
- name: "Active",
330
- filterName: "active",
331
- type: "boolean",
332
- value: true,
333
- isAList: false,
334
- },
335
- ];
336
-
337
- const result = await getSuppliers(
338
- filters,
339
- 1,
340
- 25,
341
- "name",
342
- "Ascending",
343
- );
344
- ```
345
-
346
- Empty filter values are ignored automatically.
347
-
348
- ## Supported filter types
349
-
350
- ```ts
351
- type FilterType =
352
- | "number"
353
- | "date"
354
- | "string"
355
- | "timespan"
356
- | "boolean"
357
- | "boolean-button"
358
- | "OptionValue";
359
- ```
360
-
361
- A filter configuration uses the following structure:
362
-
363
- ```ts
364
- interface FilterFormValues<TQuery> {
365
- name: string;
366
- filterName: keyof TQuery;
367
- filterNameMax?: keyof TQuery;
368
- type: FilterType;
369
- value:
370
- | number
371
- | string
372
- | Date
373
- | boolean
374
- | null
375
- | OptionValue[]
376
- | string[];
377
- maxValue?: number | string | Date | null;
378
- isAList: boolean;
379
- }
380
- ```
381
-
382
- ## Range filters
383
-
384
- Use `filterNameMax` and `maxValue` to create range filters:
385
-
386
- ```ts
387
- const filters: FilterFormValues<GetSuppliersQuery>[] = [
388
- {
389
- name: "Minimum rating",
390
- filterName: "minimumRating",
391
- filterNameMax: "maximumRating",
392
- type: "number",
393
- value: 3,
394
- maxValue: 5,
395
- isAList: false,
396
- },
397
- ];
398
- ```
399
-
400
- ## Option filters
401
-
402
- Option-based filters display a name while sending a separate value to the API.
403
-
404
- ```ts
405
- import type {
406
- FilterFormValues,
407
- OptionValue,
408
- } from "typedapi-client-helpers";
409
-
410
- const countries: OptionValue[] = [
411
- {
412
- name: "Netherlands",
413
- value: "NL",
414
- },
415
- {
416
- name: "Belgium",
417
- value: "BE",
418
- },
419
- ];
420
-
421
- const filters: FilterFormValues<GetSuppliersQuery>[] = [
422
- {
423
- name: "Countries",
424
- filterName: "countryCodes",
425
- type: "OptionValue",
426
- value: countries,
427
- isAList: true,
428
- },
429
- ];
430
- ```
431
-
432
- The generator sends the values `"NL"` and `"BE"` rather than the display names.
433
-
434
- ## Using `buildQuery` directly
435
-
436
- The `buildQuery` helper can also be used without generated filter-form methods.
437
-
438
- ```ts
439
- import {
440
- buildQuery,
441
- type FilterFormValues,
442
- } from "typedapi-client-helpers";
443
-
444
- interface ProductQuery {
445
- name?: string;
446
- minimumPrice?: number;
447
- maximumPrice?: number;
448
- pageNumber?: number;
449
- pageSize?: number;
450
- sortBy?: string;
451
- sortDirection?: string;
452
- }
453
-
454
- const filters: FilterFormValues<ProductQuery>[] = [
455
- {
456
- name: "Name",
457
- filterName: "name",
458
- type: "string",
459
- value: "Laptop",
460
- isAList: false,
461
- },
462
- {
463
- name: "Price",
464
- filterName: "minimumPrice",
465
- filterNameMax: "maximumPrice",
466
- type: "number",
467
- value: 500,
468
- maxValue: 1500,
469
- isAList: false,
470
- },
471
- ];
472
-
473
- const query = buildQuery<ProductQuery>(
474
- filters,
475
- 1,
476
- 25,
477
- "name",
478
- "Ascending",
479
- );
480
- ```
481
-
482
- The result is equivalent to:
483
-
484
- ```ts
485
- {
486
- name: "Laptop",
487
- minimumPrice: 500,
488
- maximumPrice: 1500,
489
- pageNumber: 1,
490
- pageSize: 25,
491
- sortBy: "name",
492
- sortDirection: "Ascending"
493
- }
494
- ```
495
-
496
- ## Sorting helpers
497
-
498
- The package includes helpers for converting between UI sort states and API sort directions.
499
-
500
- ```ts
501
- import {
502
- getSortDirectionFromSortType,
503
- getSortTypeFromSortDirection,
504
- } from "typedapi-client-helpers";
505
-
506
- const apiDirection =
507
- getSortDirectionFromSortType("Neutral");
508
-
509
- // "Default"
510
-
511
- const uiSortType =
512
- getSortTypeFromSortDirection("Descending");
513
-
514
- // "Descending"
515
- ```
516
-
517
- Supported UI sort states are:
518
-
519
- ```ts
520
- type SortType =
521
- | "Default"
522
- | "Neutral"
523
- | "Ascending"
524
- | "Descending";
525
- ```
526
-
527
- `Neutral` is a UI-only state and is converted to `Default` before it is sent to the API.
528
-
529
- ## File uploads
530
-
531
- Multipart methods are detected during generation. Their payloads are converted to `FormData` automatically.
532
-
533
- ```ts
534
- import { uploadDocument } from "./api";
535
-
536
- const result = await uploadDocument({
537
- file: selectedFile,
538
- description: "Supplier contract",
539
- });
540
- ```
541
-
542
- The `toFormData` helper supports:
543
-
544
- * `File`
545
- * `Blob`
546
- * Arrays of files or values
547
- * Strings
548
- * Numbers
549
- * Booleans
550
- * Nested objects
551
-
552
- Nested objects are serialized as JSON strings.
553
-
554
- You can also use the helper directly:
555
-
556
- ```ts
557
- import { toFormData } from "typedapi-client-helpers";
558
-
559
- const formData = toFormData({
560
- file: selectedFile,
561
- tags: ["contract", "supplier"],
562
- metadata: {
563
- department: "Purchasing",
564
- },
565
- });
566
- ```
567
-
568
- ## Handling HTTP responses directly
569
-
570
- The `handleApiResponse` helper can wrap any compatible generated HTTP request:
571
-
572
- ```ts
573
- import {
574
- handleApiResponse,
575
- type HttpResponse,
576
- } from "typedapi-client-helpers";
577
-
578
- interface Product {
579
- id: string;
580
- name: string;
581
- }
582
-
583
- async function requestProduct(): Promise<
584
- HttpResponse<Product>
585
- > {
586
- // Return a compatible generated HTTP response.
587
- throw new Error("Implement request");
588
- }
589
-
590
- const result = await handleApiResponse(
591
- () => requestProduct(),
592
- {
593
- onSuccess: (product) => {
594
- console.log(product);
595
- },
596
- onError: (error) => {
597
- console.error(error);
598
- },
599
- },
600
- );
601
- ```
602
-
603
- The response body is parsed as JSON when the response content type contains `application/json`. Empty responses, including HTTP `204` responses, return `undefined`.
604
-
605
- ## Regenerating the client
606
-
607
- Run the generator whenever the OpenAPI document changes:
608
-
609
- ```bash
610
- npm run generate:api
611
- ```
612
-
613
- The existing generated and method directories inside the configured API output are replaced during generation. Keep custom application code outside those generated directories.
614
-
615
- ## Recommended workflow
616
-
617
- 1. Start the backend API.
618
- 2. Confirm that its OpenAPI document is available.
619
- 3. Run the API generator.
620
- 4. Build or start the frontend application.
621
-
622
- Example:
623
-
624
- ```bash
625
- npm run generate:api
626
- npm run dev
627
- ```
628
-
629
- ## Package exports
630
-
631
- The package exports the following reusable types and helpers:
632
-
633
- ```ts
634
- import {
635
- buildQuery,
636
- getSortDirectionFromSortType,
637
- getSortTypeFromSortDirection,
638
- handleApiResponse,
639
- sortTypes,
640
- toFormData,
641
- } from "typedapi-client-helpers";
642
-
643
- import type {
644
- ApiErrorHandler,
645
- ApiMethodCallbacks,
646
- ApiResult,
647
- ApiSuccessHandler,
648
- FilterFormValues,
649
- FilterType,
650
- HttpResponse,
651
- OptionValue,
652
- SortType,
653
- } from "typedapi-client-helpers";
654
- ```
655
-
656
- Generated API models and methods are written into your project and should be imported from your configured API output directory:
657
-
658
- ```ts
659
- import {
660
- createSupplier,
661
- getSuppliers,
662
- type SupplierModel,
663
- } from "./api";
664
- ```
665
-
666
- ## TypeScript
667
-
668
- The package includes generated declaration files and can be used directly in TypeScript projects.
669
-
670
- ```ts
671
- import type {
672
- ApiResult,
673
- FilterFormValues,
674
- SortType,
675
- } from "typedapi-client-helpers";
676
- ```
1
+ # typedapi-client-helpers
2
+
3
+ `typedapi-client-helpers` generates a typed TypeScript API client from an OpenAPI/Swagger document and adds reusable helper types and functions for API results, callbacks, filtering, sorting, request parameters, and multipart uploads.
4
+
5
+ The package is meant for frontend projects that want a generated API client while still keeping the generated files inside their own source tree.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install typedapi-client-helpers
11
+ ```
12
+
13
+ ## Basic usage
14
+
15
+ Add a generator script to your project:
16
+
17
+ ```json
18
+ {
19
+ "scripts": {
20
+ "generate:api": "typedapi-generate"
21
+ }
22
+ }
23
+ ```
24
+
25
+ Run the generator:
26
+
27
+ ```bash
28
+ npm run generate:api
29
+ ```
30
+
31
+ By default the generator reads the Swagger document from `https://localhost:7000/swagger/v1/swagger.json` and writes the generated API client to `src/api`.
32
+
33
+ ## Configuration
34
+
35
+ Configuration can be supplied in the `config` section of your `package.json`, with environment variables, or with npm command-line arguments.
36
+
37
+ ### Package configuration
38
+
39
+ ```json
40
+ {
41
+ "config": {
42
+ "swaggerUrl": "https://localhost:7000/swagger/v1/swagger.json",
43
+ "swaggerFile": "swagger/openapi.json",
44
+ "apiOutput": "src/api",
45
+ "typedApiUseTypeOnlyImports": true,
46
+ "typedApiUseFilterFormValues": false,
47
+ "typedApiDefaultFunctionsPath": "../../defaultApiFunctions",
48
+ "typedApiDefaultSuccessHandler": "handleGoodResult",
49
+ "typedApiDefaultErrorHandler": "handleErrors"
50
+ }
51
+ }
52
+ ```
53
+
54
+ `swaggerFile` takes precedence over `swaggerUrl` when both are configured.
55
+
56
+ ### Configuration options
57
+
58
+ | Option | Default | Description |
59
+ | ------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
60
+ | `swaggerUrl` | `https://localhost:7000/swagger/v1/swagger.json` | URL of the OpenAPI/Swagger document. |
61
+ | `swaggerFile` | none | Local path to an OpenAPI/Swagger document. When set, this is used instead of `swaggerUrl`. |
62
+ | `apiOutput` | `src/api` | Directory where the generated API files are written. |
63
+ | `typedApiUseTypeOnlyImports` | `false` | Generates `import type` statements for imports that are only used as types. |
64
+ | `typedApiUseFilterFormValues` | `false` | Generates paginated methods that accept `FilterFormValues[]`, page values, and sort values instead of a prebuilt query object. |
65
+ | `typedApiDefaultFunctionsPath` | `../../defaultApiFunctions` | Import path used by generated method files for shared success and error handlers. |
66
+ | `typedApiDefaultSuccessHandler` | `handleGoodResult` | Name of the default success handler function imported into generated methods. |
67
+ | `typedApiDefaultErrorHandler` | `handleErrors` | Name of the default error handler function imported into generated methods. |
68
+
69
+ ### Environment variables
70
+
71
+ | Environment variable | Description |
72
+ | ---------------------------------- | --------------------------------------------------------------- |
73
+ | `SWAGGER_URL` | URL of the OpenAPI/Swagger document. |
74
+ | `SWAGGER_FILE` | Local path to an OpenAPI/Swagger document. |
75
+ | `API_OUTPUT` | Directory where generated API files are written. |
76
+ | `TYPED_API_USE_TYPE_ONLY_IMPORTS` | Enables type-only imports when set to `true`. |
77
+ | `TYPED_API_USE_FILTER_FORM_VALUES` | Enables filter-form based paginated methods when set to `true`. |
78
+
79
+ Example:
80
+
81
+ ```bash
82
+ SWAGGER_URL=https://localhost:7000/swagger/v1/swagger.json npm run generate:api
83
+ ```
84
+
85
+ ### Command-line npm config
86
+
87
+ ```bash
88
+ npm run generate:api --swagger-url=https://localhost:7000/swagger/v1/swagger.json
89
+ npm run generate:api --swagger-file=swagger/openapi.json
90
+ npm run generate:api --api-output=src/api
91
+ ```
92
+
93
+ ## Generated structure
94
+
95
+ Running the generator creates a structure similar to this:
96
+
97
+ ```text
98
+ src/
99
+ └── api/
100
+ ├── generated/
101
+ │ ├── data-contracts.ts
102
+ │ ├── http-client.ts
103
+ │ ├── Product.ts
104
+ │ └── Supplier.ts
105
+ ├── methods/
106
+ │ ├── Product.api.ts
107
+ │ └── Supplier.api.ts
108
+ └── index.ts
109
+ ```
110
+
111
+ | Folder or file | Description |
112
+ | ------------------------ | --------------------------------------------------------------------------------------------------------------- |
113
+ | `generated/` | Raw client, models, route classes, and HTTP client generated by `swagger-typescript-api`. |
114
+ | `methods/` | Typed wrapper methods generated by this package. These call the raw generated client and return `ApiResult<T>`. |
115
+ | `index.ts` | Barrel file that exports generated contracts, HTTP client types, and wrapper methods. |
116
+ | `defaultApiFunctions.ts` | Optional shared success and error handlers created when the configured default handler file does not exist. |
117
+
118
+ ## Calling generated methods
119
+
120
+ Generated wrapper methods return `ApiResult<T>`.
121
+
122
+ ```ts
123
+ import { getSuppliers } from "./api";
124
+
125
+ const result = await getSuppliers({
126
+ pageNumber: 1,
127
+ pageSize: 25,
128
+ });
129
+
130
+ if (result.ok) {
131
+ console.log(result.response);
132
+ } else {
133
+ console.error(result.status, result.error);
134
+ }
135
+ ```
136
+
137
+ Checking `result.ok` narrows the result automatically.
138
+
139
+ ## Success and error callbacks
140
+
141
+ Callbacks receive the full result object, not just the raw response or error.
142
+
143
+ ```ts
144
+ import type { ApiErrorResult, ApiSuccessResult } from "typedapi-client-helpers";
145
+ import { getSuppliers, type SupplierListResponse } from "./api";
146
+
147
+ function onSuccess(result: ApiSuccessResult<SupplierListResponse>) {
148
+ console.log(result.status, result.response);
149
+ }
150
+
151
+ function onError(result: ApiErrorResult<SupplierListResponse>) {
152
+ console.error(result.status, result.error);
153
+ }
154
+
155
+ await getSuppliers({ pageNumber: 1, pageSize: 25 }, onSuccess, onError);
156
+ ```
157
+
158
+ The generated method still returns `ApiResult<T>` after callbacks run.
159
+
160
+ ## Custom request parameters
161
+
162
+ The final wrapper argument can contain request parameters supported by the generated HTTP client.
163
+
164
+ ```ts
165
+ const result = await getSuppliers(
166
+ { pageNumber: 1, pageSize: 25 },
167
+ undefined,
168
+ undefined,
169
+ {
170
+ headers: {
171
+ Authorization: `Bearer ${token}`,
172
+ },
173
+ },
174
+ );
175
+ ```
176
+
177
+ ## Filter-form generation
178
+
179
+ Set `typedApiUseFilterFormValues` to `true` to generate paginated methods that accept filter form values.
180
+
181
+ ```json
182
+ {
183
+ "config": {
184
+ "typedApiUseFilterFormValues": true
185
+ }
186
+ }
187
+ ```
188
+
189
+ Example:
190
+
191
+ ```ts
192
+ import type { FilterFormValues } from "typedapi-client-helpers";
193
+ import { getSuppliers, type GetSuppliersQuery } from "./api";
194
+
195
+ const filters: FilterFormValues<GetSuppliersQuery>[] = [
196
+ {
197
+ name: "Supplier name",
198
+ filterName: "name",
199
+ type: "string",
200
+ value: "Example",
201
+ isAList: false,
202
+ },
203
+ ];
204
+
205
+ const result = await getSuppliers(filters, 1, 25, "name", "Ascending");
206
+ ```
207
+
208
+ Empty filter values are ignored by `buildQuery`.
209
+
210
+ ## Multipart uploads
211
+
212
+ Generated methods that need multipart bodies can use `toFormData` internally. You can also use it directly:
213
+
214
+ ```ts
215
+ import { toFormData } from "typedapi-client-helpers";
216
+
217
+ const body = toFormData({
218
+ name: "Manual",
219
+ file,
220
+ tags: ["docs", "public"],
221
+ });
222
+ ```
223
+
224
+ Arrays are appended as repeated fields, files keep their filename, primitives become strings, and nested objects are JSON-stringified.
225
+
226
+ ## Public API reference
227
+
228
+ ### Result types
229
+
230
+ | Export | Description |
231
+ | --------------------- | --------------------------------------------------------------------------------------------------------------- |
232
+ | `ApiResult<T>` | Discriminated union returned by generated wrapper methods. Contains either a success branch or an error branch. |
233
+ | `ApiSuccessResult<T>` | Success-only branch of `ApiResult<T>`. Useful for success callbacks and helper functions. |
234
+ | `ApiErrorResult<T>` | Error-only branch of `ApiResult<T>`. Useful for error callbacks and helper functions. |
235
+
236
+ ### Filter and sort types
237
+
238
+ | Export | Description |
239
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------- |
240
+ | `FilterType` | Union of supported filter input types: number, date, string, timespan, boolean, boolean-button, and OptionValue. |
241
+ | `OptionValue` | Option object with a display `name` and submitted `value`. |
242
+ | `FilterFormValues<TQuery>` | Configuration object for one filter field mapped to a query property. |
243
+ | `SortType` | UI sort state: Default, Neutral, Ascending, or Descending. |
244
+ | `SortDirection` | Sort direction value accepted by generated query objects. Supports string or number values. |
245
+ | `ApiSortDirection` | Sort direction values accepted by the generated API: Default, Ascending, or Descending. |
246
+ | `sortTypes` | Constant list of all supported UI sort states. |
247
+
248
+ ### Callback and method types
249
+
250
+ | Export | Description |
251
+ | ------------------------------- | -------------------------------------------------------------------------------------------- |
252
+ | `ApiSuccessHandler<TResponse>` | Callback type for successful API results. |
253
+ | `ApiErrorHandler<TResponse>` | Callback type for failed API results. |
254
+ | `ApiMethodCallbacks<TResponse>` | Object shape for optional success callback, error callback, and request params. |
255
+ | `ExtractResponse<T>` | Extracts the response body type from a generated method promise. |
256
+ | `ExtractError<T>` | Extracts the error body type from a generated method promise. |
257
+ | `UnwrapArray<T>` | Extracts the item type from an array, otherwise keeps the original type. |
258
+ | `ExtractDataIfPaginated<T>` | Extracts the item type from a `{ data?: T[] }` paginated response. |
259
+ | `SortableKeys<T>` | Produces keys that can be used as sortable fields for a response type. |
260
+ | `WithoutRequestParams<T>` | Removes a trailing optional `RequestParams` argument from a generated method argument tuple. |
261
+
262
+ ### HTTP types
263
+
264
+ | Export | Description |
265
+ | ---------------------- | ------------------------------------------------------------------- |
266
+ | `HttpResponse<D, E>` | Extended fetch `Response` with typed `data` and `error` properties. |
267
+ | `RuntimeRequestParams` | Runtime request options object forwarded to generated API methods. |
268
+
269
+ ### Utility functions
270
+
271
+ | Export | Description |
272
+ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
273
+ | `buildQuery<TQuery, TSortModel>()` | Builds a query object from filter form values, page values, and sort values. |
274
+ | `extractArgsCallbacksAndParams()` | Splits wrapper arguments into original API arguments, success callback, error callback, and request params. |
275
+ | `extractArgsToastsAndParams()` | Backwards-compatible alias-style extractor for wrapper arguments with success/error handlers and request params. |
276
+ | `handleApiResponse()` | Executes a generated API call and converts the response or thrown error into `ApiResult<T>`. |
277
+ | `getSortTypeFromSortDirection()` | Converts an API sort direction into a UI `SortType`. |
278
+ | `getSortDirectionFromSortType()` | Converts a UI `SortType` into an API sort direction. |
279
+ | `toFormData()` | Converts an object payload into `FormData`. |
280
+
281
+ ### Default callback functions
282
+
283
+ | Export | Description |
284
+ | ----------------------- | ------------------------------------------------------------------------------------------------------ |
285
+ | `handleGoodResult<T>()` | Default success handler template created for generated projects. It can be customized by the consumer. |
286
+ | `handleErrors<T>()` | Default error handler template created for generated projects. It can be customized by the consumer. |
287
+
288
+ ## Folder documentation
289
+
290
+ Additional README files are included in these folders:
291
+
292
+ | File | Description |
293
+ | -------------------------- | ----------------------------------------------------------- |
294
+ | `src/interfaces/README.md` | Documents exported interfaces and result/filter/sort types. |
295
+ | `src/types/README.md` | Documents helper types used by generated wrapper methods. |
296
+ | `src/utils/README.md` | Documents runtime helper functions. |
297
+ | `scripts/README.md` | Documents the API generator script. |
298
+ | `bin/README.md` | Documents the command-line entry point. |
299
+
300
+ ## Build the package
301
+
302
+ ```bash
303
+ npm run build
304
+ ```
305
+
306
+ ## Generate an API client while developing this package
307
+
308
+ ```bash
309
+ npm run generate:api
310
+ ```
311
+
312
+ ## Notes
313
+
314
+ Generated files inside `src/api` and `dist/api` depend on the Swagger document used during generation. Their exact method names, model names, and route files will change when the OpenAPI document changes.