@@ -6,24 +6,26 @@ import {
66 Delete ,
77 ExecutionContext ,
88 Get ,
9- HttpException ,
109 Injectable ,
1110 NestInterceptor ,
1211 Patch ,
1312 Post ,
1413 Put ,
14+ SetMetadata ,
1515 UseInterceptors ,
1616} from '@nestjs/common' ;
1717import {
1818 AppRoute ,
1919 AppRouteMutation ,
2020 checkZodSchema ,
21- getPathParamsFromUrl ,
2221 PathParamsWithCustomValidators ,
2322 Without ,
2423 ZodInferOrType ,
2524} from '@ts-rest/core' ;
2625import { map , Observable } from 'rxjs' ;
26+ import type { Request , Response } from 'express-serve-static-core' ;
27+
28+ const tsRestAppRouteMetadataKey = Symbol ( 'ts-rest-app-route' ) ;
2729
2830type BodyWithoutFileIfMultiPart < T extends AppRouteMutation > =
2931 T [ 'contentType' ] extends 'multipart/form-data'
@@ -41,33 +43,20 @@ export type ApiDecoratorShape<TRoute extends AppRoute> = Without<
4143 never
4244> ;
4345
44- const getQueryParams = ( url : string ) : Record < string , string > => {
45- const searchParams = new URLSearchParams ( url . split ( '?' ) [ 1 ] ) ;
46- const queryParams : Record < string , string > = { } ;
47-
48- for ( const [ key , value ] of searchParams ) {
49- queryParams [ key ] = value ;
50- }
51-
52- return queryParams ;
53- } ;
54-
5546export const ApiDecorator = createParamDecorator (
5647 ( _ : unknown , ctx : ExecutionContext ) : ApiDecoratorShape < any > => {
57- const req = ctx . switchToHttp ( ) . getRequest ( ) ;
58-
59- const appRoute = req . appRoute as AppRoute | undefined ;
48+ const req : Request = ctx . switchToHttp ( ) . getRequest ( ) ;
49+ const appRoute : AppRoute | undefined = Reflect . getMetadata (
50+ tsRestAppRouteMetadataKey ,
51+ ctx . getHandler ( )
52+ ) ;
6053
6154 if ( ! appRoute ) {
62- throw new BadRequestException (
63- 'Make sure your route is decorated with @Api()'
64- ) ;
55+ // this will respond with a 500 error without revealing this error message in the response body
56+ throw new Error ( 'Make sure your route is decorated with @Api()' ) ;
6557 }
6658
67- const pathParams = getPathParamsFromUrl ( req . url , appRoute ) ;
68- const queryParams = getQueryParams ( req . url ) ;
69-
70- const queryResult = checkZodSchema ( queryParams , appRoute . query ) ;
59+ const queryResult = checkZodSchema ( req . query , appRoute . query ) ;
7160
7261 if ( ! queryResult . success ) {
7362 throw new BadRequestException ( queryResult . error ) ;
@@ -82,7 +71,7 @@ export const ApiDecorator = createParamDecorator(
8271 throw new BadRequestException ( bodyResult . error ) ;
8372 }
8473
85- const pathParamsResult = checkZodSchema ( pathParams , appRoute . pathParams , {
74+ const pathParamsResult = checkZodSchema ( req . params , appRoute . pathParams , {
8675 passThroughExtraKeys : true ,
8776 } ) ;
8877
@@ -115,12 +104,8 @@ const getMethodDecorator = (appRoute: AppRoute) => {
115104
116105@Injectable ( )
117106export class ApiRouteInterceptor implements NestInterceptor {
118- constructor ( private readonly appRoute : AppRoute ) { }
119-
120107 intercept ( context : ExecutionContext , next : CallHandler ) : Observable < any > {
121- const req = context . switchToHttp ( ) . getRequest ( ) ;
122-
123- req . appRoute = this . appRoute ;
108+ const res : Response = context . switchToHttp ( ) . getResponse ( ) ;
124109
125110 return next . handle ( ) . pipe (
126111 map ( ( value ) => {
@@ -129,7 +114,8 @@ export class ApiRouteInterceptor implements NestInterceptor {
129114 typeof value . status === 'number' &&
130115 value . body !== undefined
131116 ) {
132- throw new HttpException ( value ?. body , value . status ) ;
117+ res . status ( value . status ) ;
118+ return value . body ;
133119 }
134120
135121 return value ;
@@ -142,8 +128,8 @@ export const Api = (appRoute: AppRoute): MethodDecorator => {
142128 const methodDecorator = getMethodDecorator ( appRoute ) ;
143129
144130 return applyDecorators (
131+ SetMetadata ( tsRestAppRouteMetadataKey , appRoute ) ,
145132 methodDecorator ,
146- // Apply the interceptor to populate req.appRoute
147- UseInterceptors ( new ApiRouteInterceptor ( appRoute ) )
133+ UseInterceptors ( ApiRouteInterceptor )
148134 ) ;
149135} ;
0 commit comments