@kubb/plugin-fetch 5.12.0-canary.20261105T084754 → 5.12.0
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/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/fetch.d.ts +13 -0
- package/docs/guides/error-handling.md +18 -0
- package/package.json +5 -5
- package/templates/fetch.ts +27 -6
package/dist/index.cjs
CHANGED
|
@@ -1511,7 +1511,7 @@ var compatibility = {
|
|
|
1511
1511
|
"node": ">=22.22"
|
|
1512
1512
|
};
|
|
1513
1513
|
// package.json
|
|
1514
|
-
var version = "5.12.0
|
|
1514
|
+
var version = "5.12.0";
|
|
1515
1515
|
// src/templates.ts
|
|
1516
1516
|
/** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */
|
|
1517
1517
|
const fetchClientTemplatePath = (0, node_url.fileURLToPath)(new URL("../templates/fetch.ts", require("url").pathToFileURL(__filename).href));
|
package/dist/index.js
CHANGED
|
@@ -1485,7 +1485,7 @@ var compatibility = {
|
|
|
1485
1485
|
"node": ">=22.22"
|
|
1486
1486
|
};
|
|
1487
1487
|
// package.json
|
|
1488
|
-
var version = "5.12.0
|
|
1488
|
+
var version = "5.12.0";
|
|
1489
1489
|
// src/templates.ts
|
|
1490
1490
|
/** Absolute path to the fetch client template, copied into `.kubb/client.ts`. */
|
|
1491
1491
|
const fetchClientTemplatePath = fileURLToPath(new URL("../templates/fetch.ts", import.meta.url));
|
|
@@ -169,6 +169,17 @@ export type ValidationErrorHandler = (error: ParseError, context: ValidationErro
|
|
|
169
169
|
} | void | Promise<{
|
|
170
170
|
value: unknown;
|
|
171
171
|
} | void>;
|
|
172
|
+
/**
|
|
173
|
+
* Turns generated validation on or off. `false` skips every validator, an object skips only the directions set to `false`:
|
|
174
|
+
* `request` is the body, `params` are path, query, and header params, `response` and `error` are the response bodies.
|
|
175
|
+
* @default true
|
|
176
|
+
*/
|
|
177
|
+
export type ValidateOption = boolean | {
|
|
178
|
+
request?: boolean;
|
|
179
|
+
params?: boolean;
|
|
180
|
+
response?: boolean;
|
|
181
|
+
error?: boolean;
|
|
182
|
+
};
|
|
172
183
|
/**
|
|
173
184
|
* A resolved security scheme carried on each generated call's `security` array and passed to the `auth` resolver.
|
|
174
185
|
*/
|
|
@@ -223,6 +234,7 @@ export type RequestConfig<TBody = unknown, TRequest = Request, TResponse = Respo
|
|
|
223
234
|
error?: Validator;
|
|
224
235
|
};
|
|
225
236
|
onValidationError?: ValidationErrorHandler;
|
|
237
|
+
validate?: ValidateOption;
|
|
226
238
|
security?: Array<Auth>;
|
|
227
239
|
auth?: AuthResolver;
|
|
228
240
|
};
|
|
@@ -246,6 +258,7 @@ export type ClientConfig<TRequest = Request, TResponse = Response> = {
|
|
|
246
258
|
serializer?: Serializers;
|
|
247
259
|
codecs?: Record<string, Codec>;
|
|
248
260
|
onValidationError?: ValidationErrorHandler;
|
|
261
|
+
validate?: ValidateOption;
|
|
249
262
|
auth?: AuthResolver;
|
|
250
263
|
};
|
|
251
264
|
/**
|
|
@@ -116,3 +116,21 @@ A `ParseError` reports schema validation issues. A `ResponseError` reports a non
|
|
|
116
116
|
|
|
117
117
|
Calling `.unwrap()` on a `throwOnError: false` call turns that same `error` into a rejection, so a
|
|
118
118
|
`try`/`catch` works there too.
|
|
119
|
+
|
|
120
|
+
## Turn validation off at runtime
|
|
121
|
+
|
|
122
|
+
The `validator` option decides at generation time which schemas each call carries. Set `validate` on the client to skip them at runtime, for example in production or in tests with partial fixtures:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { client } from './gen/.kubb/client'
|
|
126
|
+
|
|
127
|
+
client.setConfig({ validate: import.meta.env.DEV })
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`validate: false` skips every schema. An object skips only the directions set to `false`: `request` (the body), `params` (path, query, and header params), `response`, and `error`:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
client.setConfig({ validate: { response: false } })
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
A per-call `validate` overrides the client setting, such as `getPetById({ path: { petId: 1 }, validate: true })`. The default is `true`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/plugin-fetch",
|
|
3
|
-
"version": "5.12.0
|
|
3
|
+
"version": "5.12.0",
|
|
4
4
|
"description": "Generate a slim, type-safe HTTP client with Kubb based on the native Fetch api.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -81,13 +81,13 @@
|
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"@kubb/kit": "^5.15.4",
|
|
84
|
-
"@kubb/plugin-ts": "^5.
|
|
85
|
-
"@kubb/plugin-zod": "^5.
|
|
84
|
+
"@kubb/plugin-ts": "^5.4.0",
|
|
85
|
+
"@kubb/plugin-zod": "^5.8.1",
|
|
86
86
|
"@kubb/renderer-jsx": "^5.15.4"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@internals/client": "0.
|
|
90
|
-
"@internals/shared": "0.
|
|
89
|
+
"@internals/client": "0.0.0",
|
|
90
|
+
"@internals/shared": "0.0.0",
|
|
91
91
|
"typescript": "^7.0.2"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {},
|
package/templates/fetch.ts
CHANGED
|
@@ -168,6 +168,13 @@ export type ValidationErrorContext = {
|
|
|
168
168
|
*/
|
|
169
169
|
export type ValidationErrorHandler = (error: ParseError, context: ValidationErrorContext) => { value: unknown } | void | Promise<{ value: unknown } | void>
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Turns generated validation on or off. `false` skips every validator, an object skips only the directions set to `false`:
|
|
173
|
+
* `request` is the body, `params` are path, query, and header params, `response` and `error` are the response bodies.
|
|
174
|
+
* @default true
|
|
175
|
+
*/
|
|
176
|
+
export type ValidateOption = boolean | { request?: boolean; params?: boolean; response?: boolean; error?: boolean }
|
|
177
|
+
|
|
171
178
|
/**
|
|
172
179
|
* A resolved security scheme carried on each generated call's `security` array and passed to the `auth` resolver.
|
|
173
180
|
*/
|
|
@@ -217,6 +224,7 @@ export type RequestConfig<TBody = unknown, TRequest = Request, TResponse = Respo
|
|
|
217
224
|
codecs?: Record<string, Codec>
|
|
218
225
|
validator?: { request?: Validator; path?: Validator; query?: Validator; headers?: Validator; response?: Validator; error?: Validator }
|
|
219
226
|
onValidationError?: ValidationErrorHandler
|
|
227
|
+
validate?: ValidateOption
|
|
220
228
|
security?: Array<Auth>
|
|
221
229
|
auth?: AuthResolver
|
|
222
230
|
}
|
|
@@ -246,6 +254,7 @@ export type ClientConfig<TRequest = Request, TResponse = Response> = {
|
|
|
246
254
|
serializer?: Serializers
|
|
247
255
|
codecs?: Record<string, Codec>
|
|
248
256
|
onValidationError?: ValidationErrorHandler
|
|
257
|
+
validate?: ValidateOption
|
|
249
258
|
auth?: AuthResolver
|
|
250
259
|
}
|
|
251
260
|
|
|
@@ -493,6 +502,10 @@ export async function resolveAuth(params: {
|
|
|
493
502
|
}
|
|
494
503
|
}
|
|
495
504
|
|
|
505
|
+
function isValidationEnabled(validate: ValidateOption | undefined, direction: 'request' | 'params' | 'response' | 'error'): boolean {
|
|
506
|
+
return typeof validate === 'object' ? validate[direction] !== false : validate !== false
|
|
507
|
+
}
|
|
508
|
+
|
|
496
509
|
async function runValidator<T>({
|
|
497
510
|
validator,
|
|
498
511
|
value,
|
|
@@ -540,10 +553,11 @@ async function resolveRequest<TBody, TRequest, TResponse>({
|
|
|
540
553
|
}: {
|
|
541
554
|
config: ClientConfig<TRequest, TResponse>
|
|
542
555
|
requestConfig: RequestConfig<TBody, TRequest, TResponse>
|
|
543
|
-
}): Promise<{ request: ResolvedRequest; codecs: Record<string, Codec
|
|
556
|
+
}): Promise<{ request: ResolvedRequest; codecs: Record<string, Codec>; validate: ValidateOption | undefined }> {
|
|
544
557
|
const { querySerializer, bodySerializer, pathSerializer } = resolveSerializers({ config, requestConfig })
|
|
545
558
|
const codecs = { ...config.codecs, ...requestConfig.codecs }
|
|
546
559
|
const onValidationError = requestConfig.onValidationError ?? config.onValidationError
|
|
560
|
+
const validate = requestConfig.validate ?? config.validate
|
|
547
561
|
const validationContext = { direction: 'request', method: requestConfig.method, url: requestConfig.url } as const
|
|
548
562
|
|
|
549
563
|
// Params are encoded before anything reads them: headers before styling, query before auth adds its values.
|
|
@@ -554,7 +568,12 @@ async function resolveRequest<TBody, TRequest, TResponse>({
|
|
|
554
568
|
}
|
|
555
569
|
const [validatedPath, validatedQuery, validatedHeaders] = await Promise.all(
|
|
556
570
|
(['path', 'query', 'headers'] as const).map((source) =>
|
|
557
|
-
runValidator({
|
|
571
|
+
runValidator({
|
|
572
|
+
validator: isValidationEnabled(validate, 'params') ? requestConfig.validator?.[source] : undefined,
|
|
573
|
+
value: paramValues[source],
|
|
574
|
+
context: { ...validationContext, source },
|
|
575
|
+
onValidationError,
|
|
576
|
+
}),
|
|
558
577
|
),
|
|
559
578
|
)
|
|
560
579
|
|
|
@@ -581,7 +600,7 @@ async function resolveRequest<TBody, TRequest, TResponse>({
|
|
|
581
600
|
}
|
|
582
601
|
|
|
583
602
|
const validatedBody = await runValidator({
|
|
584
|
-
validator: requestConfig.validator?.request,
|
|
603
|
+
validator: isValidationEnabled(validate, 'request') ? requestConfig.validator?.request : undefined,
|
|
585
604
|
value: requestConfig.body,
|
|
586
605
|
context: { ...validationContext, source: 'body' },
|
|
587
606
|
onValidationError,
|
|
@@ -615,6 +634,7 @@ async function resolveRequest<TBody, TRequest, TResponse>({
|
|
|
615
634
|
|
|
616
635
|
return {
|
|
617
636
|
codecs,
|
|
637
|
+
validate,
|
|
618
638
|
request: {
|
|
619
639
|
url,
|
|
620
640
|
method: (requestConfig.method ?? 'GET').toUpperCase(),
|
|
@@ -645,7 +665,7 @@ export function createClientCore<TRequest = Request, TResponse = Response>(
|
|
|
645
665
|
|
|
646
666
|
const client = (async <TBody = unknown>(requestConfig: RequestConfig<TBody, TRequest, TResponse>): Promise<CallResult<TRequest, TResponse>> => {
|
|
647
667
|
const transport = requestConfig.transport ?? config.transport ?? defaultTransport
|
|
648
|
-
const { request, codecs } = await resolveRequest({ config, requestConfig })
|
|
668
|
+
const { request, codecs, validate } = await resolveRequest({ config, requestConfig })
|
|
649
669
|
|
|
650
670
|
const resolvedRequest = await interceptors.request.run(request, requestConfig)
|
|
651
671
|
const result = await interceptors.response.run(await transport(resolvedRequest), requestConfig)
|
|
@@ -654,13 +674,14 @@ export function createClientCore<TRequest = Request, TResponse = Response>(
|
|
|
654
674
|
const validator = requestConfig.validator
|
|
655
675
|
const onValidationError = requestConfig.onValidationError ?? config.onValidationError
|
|
656
676
|
const isSuccess = result.status >= 200 && result.status < 300
|
|
677
|
+
const direction = isSuccess ? 'response' : 'error'
|
|
657
678
|
const contentType = result.contentType ?? getResponseContentType(result.headers)
|
|
658
679
|
const codec = contentType ? codecs[contentType] : undefined
|
|
659
680
|
const decoded = contentType && codec?.deserialize ? await codec.deserialize(result.data, contentType) : result.data
|
|
660
681
|
const data = await runValidator({
|
|
661
|
-
validator:
|
|
682
|
+
validator: isValidationEnabled(validate, direction) ? validator?.[direction] : undefined,
|
|
662
683
|
value: decoded,
|
|
663
|
-
context: { direction
|
|
684
|
+
context: { direction, source: 'body', method: resolvedRequest.method, url: resolvedRequest.url, status: result.status },
|
|
664
685
|
onValidationError,
|
|
665
686
|
})
|
|
666
687
|
if (!isSuccess && throwOnError) {
|