snap-on-openapi 1.0.14 → 1.0.15

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/OpenApi.d.ts CHANGED
@@ -22,6 +22,7 @@ import { InitialBuilder } from './types/InitialBuilder.js';
22
22
  import { DefaultRouteContextMap } from './services/ConfigBuilder/types/DefaultRouteContextMap.js';
23
23
  import { DefaultRouteParamsMap } from './services/ConfigBuilder/types/DefaultRouteParamsMap.js';
24
24
  import z from 'zod';
25
+ import { RouteResponse } from './types/RouteResponse.js';
25
26
  export declare class OpenApi<TRouteTypes extends string, TErrorCodes extends string, TConfig extends AnyConfig<TRouteTypes, TErrorCodes>> {
26
27
  static readonly builder: InitialBuilder;
27
28
  readonly validators: ValidationUtils;
@@ -46,11 +47,7 @@ export declare class OpenApi<TRouteTypes extends string, TErrorCodes extends str
46
47
  mergePaths(...paths: RoutePath[]): RoutePath;
47
48
  addServer(url: string, description: string): void;
48
49
  protected getRouteForPath(path: string, method: string): AnyRoute<TRouteTypes> | null;
49
- processRootRoute(originalReq: Request): Promise<{
50
- status: number;
51
- body: unknown;
52
- headers: Record<string, string>;
53
- }>;
50
+ processRootRoute(originalReq: Request): Promise<RouteResponse>;
54
51
  protected handleError(e: unknown, req: Request): Promise<{
55
52
  status: number;
56
53
  body: z.TypeOf<import("./index.js").OpenApiErrorConfigMap<TErrorCodes>[TErrorCodes]["responseValidator"]>;
package/dist/OpenApi.js CHANGED
@@ -229,37 +229,51 @@ export class OpenApi {
229
229
  body: bodyData,
230
230
  },
231
231
  };
232
- const response = await route.handler({
233
- ...context,
232
+ const wrapper = this.config.routes[route.type].handlerWrapper ?? (async (handler) => handler());
233
+ const handler = async () => {
234
+ const response = await route.handler({
235
+ ...context,
236
+ params: {
237
+ query: query.data,
238
+ path: path.data,
239
+ body: bodyData,
240
+ },
241
+ });
242
+ return response;
243
+ };
244
+ const response = await wrapper(handler, {
245
+ route: route,
246
+ request: originalReq,
247
+ logger: this.logger,
234
248
  params: {
235
249
  query: query.data,
236
250
  path: path.data,
237
251
  body: bodyData,
238
252
  },
239
- });
240
- const finalResponse = route.validators.responseHeaders ? response : { body: response, headers: {} };
253
+ }, context);
241
254
  const finalResponseValidator = z.object({
242
255
  body: route.validators.response ?? z.undefined(),
243
256
  headers: route.validators.responseHeaders?.strict() ?? z.object({}),
257
+ status: z.literal(200),
244
258
  });
245
259
  const onResponse = {
246
260
  ...onHandler,
247
- response: { status: 200, body: finalResponse.body, headers: finalResponse.headers },
261
+ response,
248
262
  };
249
263
  if (this.config.disableResponseValidation) {
250
264
  if (this.config.onResponse) {
251
265
  await this.config.onResponse(onResponse);
252
266
  }
253
- return { status: 200, body: finalResponse.body, headers: finalResponse.headers };
267
+ return response;
254
268
  }
255
- const validated = finalResponseValidator.safeParse(finalResponse);
269
+ const validated = finalResponseValidator.safeParse(response);
256
270
  if (!validated.success) {
257
- throw new ValidationError(validated.error, ValidationLocation.Response, finalResponse);
271
+ throw new ValidationError(validated.error, ValidationLocation.Response, response);
258
272
  }
259
273
  if (this.config.onResponse) {
260
274
  await this.config.onResponse(onResponse);
261
275
  }
262
- return { status: 200, body: validated.data.body, headers: validated.data.headers };
276
+ return response;
263
277
  }
264
278
  catch (e) {
265
279
  return await this.handleError(e, originalReq);
@@ -3,8 +3,10 @@ import { Method } from '../../enums/Methods.js';
3
3
  import { Route } from '../../types/Route.js';
4
4
  import { AnyConfig } from '../../types/config/AnyConfig.js';
5
5
  import { RouteExtraProps } from '../../types/config/RouteExtraProps.js';
6
+ import { StandardRoute } from './types/StandardRoute.js';
6
7
  export declare class RoutingFactory<TRouteTypes extends string, TErrorCodes extends string, TConfig extends AnyConfig<TRouteTypes, TErrorCodes>> {
7
8
  protected map: TConfig;
8
9
  constructor(map: TConfig);
9
- createRoute<TType extends TRouteTypes, TMethod extends Method, TResponseValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined = undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined = undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined = undefined>(params: Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator, TMethod> & (RouteExtraProps<TConfig['routes'][TType]['extraProps']>)): Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator>;
10
+ createCustomRoute<TType extends TRouteTypes, TMethod extends Method, TResponseValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined = undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined = undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined = undefined>(params: Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator, TMethod> & (RouteExtraProps<TConfig['routes'][TType]['extraProps']>)): Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator>;
11
+ createRoute<TType extends TRouteTypes, TMethod extends Method, TResponseValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined = undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined = undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined = undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined = undefined>(params: StandardRoute<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TMethod> & (RouteExtraProps<TConfig['routes'][TType]['extraProps']>)): Route<TType, Awaited<ReturnType<TConfig['routes'][TType]['contextFactory']>>, TResponseValidator, TPathValidator, TQueryValidator, TBodyValidator, TResponseHeadersValidator>;
10
12
  }
@@ -3,7 +3,7 @@ export class RoutingFactory {
3
3
  constructor(map) {
4
4
  this.map = map;
5
5
  }
6
- createRoute(params) {
6
+ createCustomRoute(params) {
7
7
  const result = {
8
8
  ...params,
9
9
  method: params.method,
@@ -21,4 +21,29 @@ export class RoutingFactory {
21
21
  };
22
22
  return result;
23
23
  }
24
+ createRoute(params) {
25
+ const newHandler = async (ctx) => {
26
+ const body = await params.handler(ctx);
27
+ return {
28
+ body: body,
29
+ status: 200,
30
+ headers: {},
31
+ };
32
+ };
33
+ const result = {
34
+ ...params,
35
+ method: params.method,
36
+ type: params.type,
37
+ path: params.path,
38
+ description: params.description,
39
+ validators: {
40
+ query: params.validators.query,
41
+ path: params.validators.path,
42
+ response: params.validators.response,
43
+ body: params.validators.body,
44
+ },
45
+ handler: newHandler,
46
+ };
47
+ return result;
48
+ }
24
49
  }
@@ -0,0 +1,26 @@
1
+ import { z, ZodFirstPartySchemaTypes, ZodObject, ZodRawShape } from 'zod';
2
+ import { Method } from '../../../enums/Methods.js';
3
+ import { RoutePath } from '../../../types/RoutePath.js';
4
+ type BodyHandlerResponse<T extends ZodFirstPartySchemaTypes | undefined = undefined> = Promise<T extends undefined ? void : z.infer<Exclude<T, undefined>>>;
5
+ export interface StandardRoute<TType extends string, TContext extends object, TResponseValidator extends ZodFirstPartySchemaTypes | undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined, TMethod extends Method = Method> {
6
+ tags?: string[];
7
+ operationId?: string;
8
+ type: TType;
9
+ method: TMethod;
10
+ path: RoutePath;
11
+ description: string;
12
+ validators: {
13
+ query?: TQueryValidator;
14
+ path?: TPathValidator;
15
+ body?: TMethod extends 'GET' ? never : TBodyValidator;
16
+ response?: TResponseValidator;
17
+ };
18
+ handler: (context: {
19
+ params: {
20
+ body: TBodyValidator extends ZodFirstPartySchemaTypes ? z.infer<TBodyValidator> : object;
21
+ query: TQueryValidator extends ZodObject<ZodRawShape> ? z.infer<TQueryValidator> : object;
22
+ path: TPathValidator extends ZodObject<ZodRawShape> ? z.infer<TPathValidator> : object;
23
+ };
24
+ } & TContext) => BodyHandlerResponse<TResponseValidator>;
25
+ }
26
+ export {};
@@ -1,12 +1,7 @@
1
1
  import { z, ZodFirstPartySchemaTypes, ZodObject, ZodRawShape } from 'zod';
2
2
  import { Method } from '../enums/Methods.js';
3
3
  import { RoutePath } from './RoutePath.js';
4
- type BodyHandlerResponse<T extends ZodFirstPartySchemaTypes | undefined = undefined> = Promise<T extends undefined ? undefined : z.infer<Exclude<T, undefined>>>;
5
- type FullHandlerRespnse<T extends ZodFirstPartySchemaTypes | undefined, THeaders extends ZodObject<ZodRawShape> | undefined> = Promise<{
6
- body: Awaited<BodyHandlerResponse<T>>;
7
- headers: z.infer<Exclude<THeaders, undefined>>;
8
- }>;
9
- type HandlerResponse<T extends ZodFirstPartySchemaTypes | undefined, TH extends ZodObject<ZodRawShape> | undefined> = TH extends undefined ? BodyHandlerResponse<T> : FullHandlerRespnse<T, Exclude<TH, undefined>>;
4
+ import { RouteResponse } from './RouteResponse.js';
10
5
  export interface Route<TType extends string, TContext extends object, TResponseValidator extends ZodFirstPartySchemaTypes | undefined, TPathValidator extends ZodObject<ZodRawShape> | undefined, TQueryValidator extends ZodObject<ZodRawShape> | undefined, TBodyValidator extends ZodFirstPartySchemaTypes | undefined, TResponseHeadersValidator extends ZodObject<ZodRawShape> | undefined, TMethod extends Method = Method> {
11
6
  tags?: string[];
12
7
  operationId?: string;
@@ -27,6 +22,5 @@ export interface Route<TType extends string, TContext extends object, TResponseV
27
22
  query: TQueryValidator extends ZodObject<ZodRawShape> ? z.infer<TQueryValidator> : object;
28
23
  path: TPathValidator extends ZodObject<ZodRawShape> ? z.infer<TPathValidator> : object;
29
24
  };
30
- } & TContext) => HandlerResponse<TResponseValidator, TResponseHeadersValidator>;
25
+ } & TContext) => Promise<RouteResponse>;
31
26
  }
32
- export {};
@@ -0,0 +1,5 @@
1
+ export interface RouteResponse {
2
+ body: unknown;
3
+ status: number;
4
+ headers: Record<string, string>;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,6 @@
1
1
  import { ZodOpenApiVersion } from 'zod-openapi';
2
2
  import { Logger } from '../../services/Logger/Logger.js';
3
3
  import { LogLevel } from '../../services/Logger/types/LogLevel.js';
4
- import { AnyRoute } from '../AnyRoute.js';
5
4
  import { RoutePath } from '../RoutePath.js';
6
5
  import { ErrorConfigMap } from './ErrorConfigMap.js';
7
6
  import { ErrorResponse } from './ErrorResponse.js';
@@ -38,9 +37,4 @@ export type Config<TRouteTypes extends string, TErrorCodes extends string, TErro
38
37
  onHandler?: (e: OnHandlerEvent) => Promise<void>;
39
38
  onResponse?: (e: OnResponseEvent) => Promise<void>;
40
39
  onError?: (e: OnErrorEvent) => Promise<ErrorResponse<TErrorCodes, TErrorConfigMap>>;
41
- middleware?: <T extends TRouteTypes>(route: AnyRoute<T>, ctx: Awaited<ReturnType<TRouteContextMap[T]>>) => Promise<{
42
- body?: unknown;
43
- status?: number;
44
- headers?: Record<string, string>;
45
- }>;
46
40
  };
@@ -1,9 +1,11 @@
1
1
  import { ZodObject, ZodRawShape } from 'zod';
2
2
  import { ContextParams } from './ContextParams.js';
3
+ import { RouteHandlerWrapper } from './RouteHandlerWrapper.js';
3
4
  export type RouteConfig<TRouteType extends string, TErrorCodes extends string, TExtraProps extends ZodObject<ZodRawShape> | undefined = ZodObject<ZodRawShape> | undefined, TContext extends object | undefined = object | undefined> = {
4
5
  authorization: boolean;
5
6
  extraProps: TExtraProps;
6
7
  contextFactory: (params: ContextParams<TRouteType, TExtraProps>) => Promise<TContext>;
8
+ handlerWrapper?: RouteHandlerWrapper<TRouteType, TExtraProps, TContext>;
7
9
  errors?: {
8
10
  [key in TErrorCodes]?: true;
9
11
  };
@@ -0,0 +1,4 @@
1
+ import { ZodObject, ZodRawShape } from 'zod';
2
+ import { ContextParams } from './ContextParams.js';
3
+ import { RouteResponse } from '../RouteResponse.js';
4
+ export type RouteHandlerWrapper<TRouteType extends string, TExtraProps extends ZodObject<ZodRawShape> | undefined, TContext extends object | undefined> = (handler: () => Promise<RouteResponse>, params: ContextParams<TRouteType, TExtraProps>, context: TContext) => Promise<RouteResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,5 @@
1
+ import { RouteResponse } from '../RouteResponse.js';
1
2
  import { OnHandlerEvent } from './OnHandlerEvent.js';
2
3
  export interface OnResponseEvent extends OnHandlerEvent {
3
- response: {
4
- status: number;
5
- body: unknown;
6
- headers: Record<string, string>;
7
- };
4
+ response: RouteResponse;
8
5
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snap-on-openapi",
3
3
  "author": "Alex Sarychev",
4
- "version": "1.0.14",
4
+ "version": "1.0.15",
5
5
  "description": "Swiftly build type-checked OpenAPI applications with Zod and TypeScript",
6
6
  "type": "module",
7
7
  "license": "ISC",