@athenna/http 4.23.0 → 4.25.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.
@@ -7,121 +7,83 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
  import { View } from '@athenna/view';
10
- export class Response {
11
- constructor(response, request) {
12
- this.response = response;
13
- this.request = request;
14
- }
15
- /**
16
- * Verify if the response has been already sent.
17
- */
18
- get sent() {
19
- return this.response.sent;
20
- }
21
- /**
22
- * Get the response body sent in response.
23
- */
24
- get body() {
25
- return this.response.body;
26
- }
27
- /**
28
- * Get the status code sent in response.
29
- */
30
- get statusCode() {
31
- return this.response.statusCode;
32
- }
33
- /**
34
- * Get the headers sent in response.
35
- */
36
- get headers() {
37
- return this.response.getHeaders();
38
- }
39
- /**
40
- * Get the time in MS of how much the request has taken to response.
41
- */
42
- get responseTime() {
43
- return this.response.elapsedTime;
44
- }
45
- /**
46
- * Terminated the request sending a view to be rendered.
47
- */
48
- async view(view, data) {
49
- const content = await View.render(view, { ...data, request: this.request });
50
- await this.safeHeader('Content-Type', 'text/html; charset=utf-8').response.send(content);
51
- this.response.body = content;
52
- return this;
53
- }
54
- /**
55
- * Terminate the request sending the response body or not.
56
- */
57
- async send(data) {
58
- await this.response.send(data);
59
- this.response.body = data;
60
- return this;
61
- }
62
- /**
63
- * Terminated the request sending a file.
64
- */
65
- async sendFile(filename, filepath, options) {
66
- await this.response.sendFile(filename, filepath, options);
67
- return this;
68
- }
69
- async download(filepath, filename, options) {
70
- await this.response.download(filename, filepath, options);
71
- return this;
72
- }
73
- /**
74
- * Set the response status code.
75
- */
76
- status(code) {
77
- this.response.status(code);
78
- return this;
79
- }
80
- /**
81
- * Add some header to the response.
82
- */
83
- header(header, value) {
84
- this.response.header(header, value);
85
- return this;
86
- }
87
- /**
88
- * Verify if response has some header.
89
- */
90
- hasHeader(header) {
91
- return this.response.hasHeader(header);
92
- }
93
- /**
94
- * Add some header safely to the response. This means that the header is not
95
- * going to be added if is already set.
96
- */
97
- safeHeader(header, value) {
98
- this.response.header(header, value);
99
- return this;
100
- }
101
- /**
102
- * Remove some header from the response.
103
- */
104
- removeHeader(header) {
105
- this.response.removeHeader(header);
106
- return this;
107
- }
108
- /**
109
- * Redirect the response to other url. You can also set a different status code
110
- * for the redirect.
111
- */
112
- async redirectTo(url, status) {
113
- if (status) {
114
- await this.response.redirect(status, url);
115
- return this;
10
+ /**
11
+ * Create the Athenna response object
12
+ */
13
+ export function response(reply, request) {
14
+ const response = {
15
+ response: reply,
16
+ request,
17
+ get sent() {
18
+ return reply.sent;
19
+ },
20
+ get body() {
21
+ return reply.body;
22
+ },
23
+ get statusCode() {
24
+ return reply.statusCode;
25
+ },
26
+ get headers() {
27
+ return reply.getHeaders();
28
+ },
29
+ get responseTime() {
30
+ return reply.elapsedTime;
31
+ },
32
+ async view(view, data) {
33
+ const content = await View.render(view, {
34
+ ...data,
35
+ request: this.request
36
+ });
37
+ await response
38
+ .safeHeader('Content-Type', 'text/html; charset=utf-8')
39
+ .response.send(content);
40
+ response.response.body = content;
41
+ return response;
42
+ },
43
+ async send(data) {
44
+ await response.response.send(data);
45
+ response.response.body = data;
46
+ return response;
47
+ },
48
+ async sendFile(filename, filepath, options) {
49
+ await response.response.sendFile(filename, filepath, options);
50
+ return response;
51
+ },
52
+ async download(filepath, filename, options) {
53
+ await response.response.download(filename, filepath, options);
54
+ return response;
55
+ },
56
+ status(code) {
57
+ response.response.status(code);
58
+ return response;
59
+ },
60
+ header(header, value) {
61
+ response.response.header(header, value);
62
+ return response;
63
+ },
64
+ hasHeader(header) {
65
+ return response.response.hasHeader(header);
66
+ },
67
+ safeHeader(header, value) {
68
+ response.response.header(header, value);
69
+ return response;
70
+ },
71
+ removeHeader(header) {
72
+ response.response.removeHeader(header);
73
+ return response;
74
+ },
75
+ async redirectTo(url, status) {
76
+ if (status) {
77
+ await this.response.redirect(status, url);
78
+ return response;
79
+ }
80
+ await this.response.redirect(url);
81
+ return response;
82
+ },
83
+ helmet(options) {
84
+ this.response.helmet(options);
85
+ return response;
116
86
  }
117
- await this.response.redirect(url);
118
- return this;
119
- }
120
- /**
121
- * Apply helmet in response.
122
- */
123
- helmet(options) {
124
- this.response.helmet(options);
125
- return this;
126
- }
87
+ };
88
+ return response;
127
89
  }
@@ -7,8 +7,8 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
  import { Is } from '@athenna/common';
10
- import { Request } from '#src/context/Request';
11
- import { Response } from '#src/context/Response';
10
+ import { request } from '#src/context/Request';
11
+ import { response } from '#src/context/Response';
12
12
  export class FastifyHandler {
13
13
  /**
14
14
  * Parse the fastify request handler and the preHandler hook to an Athenna
@@ -16,20 +16,14 @@ export class FastifyHandler {
16
16
  */
17
17
  static request(handler) {
18
18
  return async (req, res) => {
19
- const request = new Request(req);
20
19
  if (!req.data) {
21
20
  req.data = {};
22
21
  }
23
- const response = new Response(res, request);
24
- await handler({
25
- request,
26
- response,
27
- data: req.data,
28
- body: req.body,
29
- params: req.params,
30
- queries: req.query,
31
- headers: req.headers
32
- });
22
+ const ctx = {};
23
+ ctx.data = req.data;
24
+ ctx.request = request(req);
25
+ ctx.response = response(res, ctx.request);
26
+ return handler(ctx);
33
27
  };
34
28
  }
35
29
  /**
@@ -43,26 +37,20 @@ export class FastifyHandler {
43
37
  */
44
38
  static intercept(handler) {
45
39
  return async (req, res, payload) => {
46
- const request = new Request(req);
47
40
  if (!req.data) {
48
41
  req.data = {};
49
42
  }
50
- const response = new Response(res, request);
51
43
  if (Is.Json(payload)) {
52
44
  payload = JSON.parse(payload);
53
45
  }
54
46
  res.body = payload;
55
- payload = await handler({
56
- request,
57
- response,
58
- status: response.statusCode,
59
- data: req.data,
60
- body: res.body,
61
- params: req.params,
62
- queries: req.query,
63
- headers: req.headers
64
- });
65
- res.body = payload;
47
+ const ctx = {};
48
+ ctx.data = req.data;
49
+ ctx.request = request(req);
50
+ ctx.response = response(res, ctx.request);
51
+ ctx.status = ctx.response.statusCode;
52
+ payload = await handler(ctx);
53
+ ctx.response.response.body = payload;
66
54
  if (Is.Object(payload)) {
67
55
  payload = JSON.stringify(payload);
68
56
  }
@@ -74,22 +62,16 @@ export class FastifyHandler {
74
62
  */
75
63
  static terminate(handler) {
76
64
  return async (req, res) => {
77
- const request = new Request(req);
78
65
  if (!req.data) {
79
66
  req.data = {};
80
67
  }
81
- const response = new Response(res, request);
82
- await handler({
83
- request,
84
- response,
85
- params: req.params,
86
- queries: req.query,
87
- data: req.data,
88
- body: res.body || req.body,
89
- headers: res.getHeaders(),
90
- status: res.statusCode,
91
- responseTime: res.elapsedTime
92
- });
68
+ const ctx = {};
69
+ ctx.data = req.data;
70
+ ctx.request = request(req);
71
+ ctx.response = response(res, ctx.request);
72
+ ctx.status = ctx.response.statusCode;
73
+ ctx.responseTime = ctx.response.elapsedTime;
74
+ await handler(ctx);
93
75
  };
94
76
  }
95
77
  /**
@@ -97,21 +79,15 @@ export class FastifyHandler {
97
79
  */
98
80
  static error(handler) {
99
81
  return async (error, req, res) => {
100
- const request = new Request(req);
101
82
  if (!req.data) {
102
83
  req.data = {};
103
84
  }
104
- const response = new Response(res, request);
105
- await handler({
106
- request,
107
- response,
108
- data: req.data,
109
- body: res.body || req.body,
110
- params: req.params,
111
- queries: req.query,
112
- headers: req.headers,
113
- error
114
- });
85
+ const ctx = {};
86
+ ctx.data = req.data;
87
+ ctx.request = request(req);
88
+ ctx.response = response(res, ctx.request);
89
+ ctx.error = error;
90
+ await handler(ctx);
115
91
  };
116
92
  }
117
93
  }
@@ -13,7 +13,7 @@ import { Log } from '@athenna/logger';
13
13
  import { Config } from '@athenna/config';
14
14
  import { sep, isAbsolute, resolve } from 'node:path';
15
15
  import { Annotation } from '@athenna/ioc';
16
- import { File, Exec, Module, String } from '@athenna/common';
16
+ import { File, Path, Exec, Module, String } from '@athenna/common';
17
17
  import { HttpExceptionHandler } from '#src/handlers/HttpExceptionHandler';
18
18
  const corsPlugin = await Module.safeImport('@fastify/cors');
19
19
  const helmetPlugin = await Module.safeImport('@fastify/helmet');
@@ -44,6 +44,16 @@ export declare class Router {
44
44
  * Creates a new route resource.
45
45
  */
46
46
  resource(resource: string, controller?: any): RouteResource;
47
+ /**
48
+ * This method is a convenient shortcut to render a view without
49
+ * defining an explicit handler.
50
+ */
51
+ view(pattern: string, view: string, data?: any): Route;
52
+ /**
53
+ * This method is a convenient shortcut to redirect a route without
54
+ * defining an explicit handler.
55
+ */
56
+ redirect(pattern: string, url: string, status?: number): Route;
47
57
  /**
48
58
  * Define a route that handles all common HTTP methods.
49
59
  */
@@ -79,6 +79,24 @@ export class Router {
79
79
  }
80
80
  return resourceInstance;
81
81
  }
82
+ /**
83
+ * This method is a convenient shortcut to render a view without
84
+ * defining an explicit handler.
85
+ */
86
+ view(pattern, view, data) {
87
+ return this.route(pattern, ['GET', 'HEAD'], ctx => {
88
+ return ctx.response.view(view, data);
89
+ });
90
+ }
91
+ /**
92
+ * This method is a convenient shortcut to redirect a route without
93
+ * defining an explicit handler.
94
+ */
95
+ redirect(pattern, url, status) {
96
+ return this.route(pattern, ['GET', 'HEAD'], ctx => {
97
+ return ctx.response.redirectTo(url, status);
98
+ });
99
+ }
82
100
  /**
83
101
  * Define a route that handles all common HTTP methods.
84
102
  */
@@ -151,17 +151,22 @@ export class ServerImpl {
151
151
  });
152
152
  return;
153
153
  }
154
- this.fastify.route({
154
+ const { middlewares, interceptors, terminators } = options.middlewares;
155
+ const route = {
155
156
  url: options.url,
156
157
  method: options.methods,
157
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
158
- // @ts-ignore
159
- handler: FastifyHandler.request(options.handler),
160
- preHandler: options.middlewares.middlewares.map(m => FastifyHandler.handle(m)),
161
- onSend: options.middlewares.interceptors.map(m => FastifyHandler.intercept(m)),
162
- onResponse: options.middlewares.terminators.map(m => FastifyHandler.terminate(m)),
163
- ...options.fastify
164
- });
158
+ handler: FastifyHandler.request(options.handler)
159
+ };
160
+ if (middlewares.length) {
161
+ route.preHandler = middlewares.map(m => FastifyHandler.handle(m));
162
+ }
163
+ if (interceptors.length) {
164
+ route.onSend = interceptors.map(i => FastifyHandler.intercept(i));
165
+ }
166
+ if (terminators.length) {
167
+ route.onResponse = terminators.map(t => FastifyHandler.terminate(t));
168
+ }
169
+ this.fastify.route({ ...route, ...options.fastify });
165
170
  }
166
171
  /**
167
172
  * Add a new GET route to the http server.