@@ -18,6 +18,18 @@ import {
1818 validateResponse ,
1919} from '@ts-rest/core' ;
2020import { getPathParamsFromArray } from './path-utils' ;
21+ import { z } from 'zod' ;
22+
23+ export class RequestValidationError extends Error {
24+ constructor (
25+ public pathParams : z . ZodError | null ,
26+ public headers : z . ZodError | null ,
27+ public query : z . ZodError | null ,
28+ public body : z . ZodError | null ,
29+ ) {
30+ super ( '[ts-rest] request validation failed' ) ;
31+ }
32+ }
2133
2234type AppRouteImplementation < T extends AppRoute > = (
2335 args : ServerInferRequest < T , NextApiRequest [ 'headers' ] > & {
@@ -177,14 +189,19 @@ export const createNextRouter = <T extends AppRouter>(
177189 options ?: {
178190 jsonQuery ?: boolean ;
179191 responseValidation ?: boolean ;
192+ throwRequestValidation ?: boolean ;
180193 errorHandler ?: (
181194 err : unknown ,
182195 req : NextApiRequest ,
183196 res : NextApiResponse
184197 ) => void ;
185198 }
186199) => {
187- const { jsonQuery = false , responseValidation = false } = options || { } ;
200+ const {
201+ jsonQuery = false ,
202+ responseValidation = false ,
203+ throwRequestValidation = false
204+ } = options || { } ;
188205
189206 const combinedRouter = mergeRouterAndImplementation ( routes , obj ) ;
190207
@@ -209,35 +226,48 @@ export const createNextRouter = <T extends AppRouter>(
209226 passThroughExtraKeys : true ,
210227 } ) ;
211228
212- if ( ! pathParamsResult . success ) {
213- return res . status ( 400 ) . json ( pathParamsResult . error ) ;
214- }
215-
216229 const headersResult = checkZodSchema ( req . headers , route . headers , {
217230 passThroughExtraKeys : true ,
218231 } ) ;
219232
220- if ( ! headersResult . success ) {
221- return res . status ( 400 ) . send ( headersResult . error ) ;
222- }
223-
224233 query = jsonQuery
225234 ? parseJsonQueryObject ( query as Record < string , string > )
226235 : req . query ;
227236
228237 const queryResult = checkZodSchema ( query , route . query ) ;
229238
230- if ( ! queryResult . success ) {
231- return res . status ( 400 ) . json ( queryResult . error ) ;
232- }
233-
234239 const bodyResult = checkZodSchema ( req . body , route . body ) ;
235240
236- if ( ! bodyResult . success ) {
237- return res . status ( 400 ) . json ( bodyResult . error ) ;
238- }
239-
240241 try {
242+ if (
243+ ! pathParamsResult . success ||
244+ ! headersResult . success ||
245+ ! queryResult . success ||
246+ ! bodyResult . success
247+ ) {
248+ if ( throwRequestValidation ) {
249+ throw new RequestValidationError (
250+ pathParamsResult . success ? null : pathParamsResult . error ,
251+ headersResult . success ? null : headersResult . error ,
252+ queryResult . success ? null : queryResult . error ,
253+ bodyResult . success ? null : bodyResult . error ,
254+ ) ;
255+ }
256+
257+ if ( ! pathParamsResult . success ) {
258+ return res . status ( 400 ) . json ( pathParamsResult . error ) ;
259+ }
260+ if ( ! headersResult . success ) {
261+ return res . status ( 400 ) . send ( headersResult . error ) ;
262+ }
263+ if ( ! queryResult . success ) {
264+ return res . status ( 400 ) . json ( queryResult . error ) ;
265+ }
266+ if ( ! bodyResult . success ) {
267+ return res . status ( 400 ) . json ( bodyResult . error ) ;
268+ }
269+ }
270+
241271 const { body, status } = await route . implementation ( {
242272 body : bodyResult . data ,
243273 query : queryResult . data ,
0 commit comments