@lucaapp/service-utils 1.26.0 → 1.27.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.
@@ -6,12 +6,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.registerEndpoint = exports.mountEndpoint = void 0;
7
7
  const zod_1 = require("zod");
8
8
  const assert_1 = __importDefault(require("assert"));
9
+ const boom_1 = require("@hapi/boom");
9
10
  const buildResponseConfig = (responseOptions) => {
10
11
  const responses = {};
11
12
  responseOptions.forEach(response => {
12
13
  responses[String(response.status)] = {
13
14
  description: response.description,
14
- ...(!(response.schema instanceof zod_1.ZodVoid) && {
15
+ ...(!(response.schema instanceof zod_1.z.ZodVoid) && {
15
16
  content: {
16
17
  'application/json': {
17
18
  schema: response.schema,
@@ -22,36 +23,114 @@ const buildResponseConfig = (responseOptions) => {
22
23
  });
23
24
  return responses;
24
25
  };
25
- const mountEndpoint = (router, method, path, options, handler) => {
26
- (0, assert_1.default)(options.responses.length > 0, 'You need to specify at least one response');
27
- router[method](path, async (request, response) => {
28
- // parse request schemas
29
- const handlerRequestBody = ((await options.schemas?.body?.parseAsync(request.body)) || undefined);
30
- const handlerRequestParams = ((await options.schemas?.params?.parseAsync(request.params)) || undefined);
31
- const handlerRequestQuery = ((await options.schemas?.query?.parseAsync(request.query)) || undefined);
32
- const handlerRequestHeaders = ((await options.schemas?.headers?.parseAsync(request.headers)) || undefined);
26
+ const validateAndSendResponse = async (expressResponse, response, validResponses) => {
27
+ (0, assert_1.default)(typeof response.status === 'number');
28
+ // get schema respective to status code
29
+ const responseSchema = validResponses.find(responseSchema => responseSchema.status === response.status);
30
+ const schema = responseSchema?.schema;
31
+ const isZodSchema = schema instanceof zod_1.z.ZodSchema;
32
+ const isZodVoid = schema instanceof zod_1.z.ZodVoid;
33
+ (0, assert_1.default)(isZodSchema || isZodVoid);
34
+ // validate response schema
35
+ const validatedResponseBody = await schema.parseAsync(response.body);
36
+ if (validatedResponseBody === undefined) {
37
+ // No Content Response
38
+ return expressResponse.status(response.status).end();
39
+ }
40
+ expressResponse.status(response.status).send(validatedResponseBody);
41
+ };
42
+ const handleMiddleware = async (middleware, context, request, response) => new Promise(async (resolve, reject) => {
43
+ try {
44
+ const handlerRequestBody = ((await middleware.options.schemas?.body?.parseAsync(request.body)) ||
45
+ undefined);
46
+ const handlerRequestParams = ((await middleware.options.schemas?.params?.parseAsync(request.params)) || undefined);
47
+ const handlerRequestQuery = ((await middleware.options.schemas?.query?.parseAsync(request.query)) ||
48
+ undefined);
49
+ const handlerRequestHeaders = ((await middleware.options.schemas?.headers?.parseAsync(request.headers)) || undefined);
33
50
  const handlerRequest = {
34
51
  body: handlerRequestBody,
35
52
  params: handlerRequestParams,
36
53
  query: handlerRequestQuery,
37
54
  headers: handlerRequestHeaders,
38
55
  };
39
- // TODO: handle middlewares and build context object
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- const ctx = {};
42
- await handler(handlerRequest, ctx, controllerResponse => {
43
- // this assertion is necessary due to the type possibly being unknown because of the edge case of an schema array with 0 elements
44
- (0, assert_1.default)(typeof controllerResponse.status === 'number');
45
- // get schema respective to status code
46
- const { schema } = options.responses.find(responseSchema => responseSchema.status === controllerResponse.status);
47
- // validate response schema
48
- const validatedResponseBody = schema.parse(controllerResponse.body);
49
- if (validatedResponseBody === undefined) {
50
- // No Content Response
51
- return response.status(controllerResponse.status).end();
56
+ await middleware.handler(handlerRequest, async (middlewareResponse) => {
57
+ try {
58
+ await validateAndSendResponse(response, middlewareResponse, middleware.options.responses);
59
+ resolve(false);
60
+ }
61
+ catch (error) {
62
+ if (error instanceof Error) {
63
+ (0, boom_1.boomify)(error, {
64
+ statusCode: 500,
65
+ });
66
+ }
67
+ reject(error);
68
+ }
69
+ }, async (returnedContext) => {
70
+ try {
71
+ const validatedContext = await middleware.options.schemas?.context?.parseAsync(returnedContext);
72
+ Object.assign(context, validatedContext);
73
+ resolve(true);
74
+ }
75
+ catch (error) {
76
+ if (error instanceof Error) {
77
+ (0, boom_1.boomify)(error, {
78
+ statusCode: 500,
79
+ });
80
+ }
81
+ reject(error);
52
82
  }
53
- response.status(controllerResponse.status).send(validatedResponseBody);
54
83
  });
84
+ }
85
+ catch (error) {
86
+ reject(error);
87
+ }
88
+ });
89
+ const mountEndpoint = (router, method, path, options, handler) => {
90
+ (0, assert_1.default)(options.responses.length > 0, 'You need to specify at least one response');
91
+ router[method](path, async (request, response, next) => {
92
+ try {
93
+ // parse request schemas
94
+ const handlerRequestBody = ((await options.schemas?.body?.parseAsync(request.body)) || undefined);
95
+ const handlerRequestParams = ((await options.schemas?.params?.parseAsync(request.params)) ||
96
+ undefined);
97
+ const handlerRequestQuery = ((await options.schemas?.query?.parseAsync(request.query)) || undefined);
98
+ const handlerRequestHeaders = ((await options.schemas?.headers?.parseAsync(request.headers)) ||
99
+ undefined);
100
+ const handlerRequest = {
101
+ body: handlerRequestBody,
102
+ params: handlerRequestParams,
103
+ query: handlerRequestQuery,
104
+ headers: handlerRequestHeaders,
105
+ };
106
+ const ctx = {};
107
+ if (options.middlewares instanceof Array) {
108
+ for (const middleware of options.middlewares) {
109
+ const shouldContinue = await handleMiddleware(middleware, ctx, request, response);
110
+ if (!shouldContinue)
111
+ return;
112
+ }
113
+ }
114
+ await handler(handlerRequest, ctx, async (controllerResponse) => {
115
+ try {
116
+ await validateAndSendResponse(response, controllerResponse, options.responses);
117
+ }
118
+ catch (error) {
119
+ if (error instanceof Error) {
120
+ (0, boom_1.boomify)(error, {
121
+ statusCode: 500,
122
+ });
123
+ }
124
+ next(error);
125
+ }
126
+ });
127
+ }
128
+ catch (error) {
129
+ if (error instanceof zod_1.z.ZodError && !(0, boom_1.isBoom)(error)) {
130
+ return response.status(400).send({ issues: error.issues });
131
+ }
132
+ next(error);
133
+ }
55
134
  });
56
135
  };
57
136
  exports.mountEndpoint = mountEndpoint;
@@ -5,12 +5,12 @@ declare const badRequestErrorSchema: z.ZodObject<{
5
5
  error: z.ZodString;
6
6
  message: z.ZodString;
7
7
  }, "strip", z.ZodTypeAny, {
8
- error: string;
9
8
  message: string;
9
+ error: string;
10
10
  statusCode: 400;
11
11
  }, {
12
- error: string;
13
12
  message: string;
13
+ error: string;
14
14
  statusCode: 400;
15
15
  }>;
16
16
  declare const unauthorizedErrorSchema: z.ZodObject<{
@@ -18,12 +18,12 @@ declare const unauthorizedErrorSchema: z.ZodObject<{
18
18
  error: z.ZodString;
19
19
  message: z.ZodString;
20
20
  }, "strip", z.ZodTypeAny, {
21
- error: string;
22
21
  message: string;
22
+ error: string;
23
23
  statusCode: 401;
24
24
  }, {
25
- error: string;
26
25
  message: string;
26
+ error: string;
27
27
  statusCode: 401;
28
28
  }>;
29
29
  declare const forbiddenErrorSchema: z.ZodObject<{
@@ -31,12 +31,12 @@ declare const forbiddenErrorSchema: z.ZodObject<{
31
31
  error: z.ZodString;
32
32
  message: z.ZodString;
33
33
  }, "strip", z.ZodTypeAny, {
34
- error: string;
35
34
  message: string;
35
+ error: string;
36
36
  statusCode: 403;
37
37
  }, {
38
- error: string;
39
38
  message: string;
39
+ error: string;
40
40
  statusCode: 403;
41
41
  }>;
42
42
  declare const notFoundErrorSchema: z.ZodObject<{
@@ -44,12 +44,12 @@ declare const notFoundErrorSchema: z.ZodObject<{
44
44
  error: z.ZodString;
45
45
  message: z.ZodString;
46
46
  }, "strip", z.ZodTypeAny, {
47
- error: string;
48
47
  message: string;
48
+ error: string;
49
49
  statusCode: 404;
50
50
  }, {
51
- error: string;
52
51
  message: string;
52
+ error: string;
53
53
  statusCode: 404;
54
54
  }>;
55
55
  export declare const okResponse: <T>(schema: z.ZodType<T, z.ZodTypeDef, T>) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "1.26.0",
3
+ "version": "1.27.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [