@athenna/http 4.24.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,210 +7,8 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
  import type { FastifyReply } from 'fastify';
10
- import type { SendOptions } from '@fastify/static';
11
- import type { Request } from '#src/context/Request';
12
- import type { FastifyHelmetOptions } from '@fastify/helmet';
13
- export declare class Response {
14
- /**
15
- * The fastify response object.
16
- */
17
- response: FastifyReply;
18
- /**
19
- * The request object from request context.
20
- */
21
- request: Request;
22
- constructor(response: FastifyReply, request?: Request);
23
- /**
24
- * Verify if the response has been already sent. Keep
25
- * in mind that this method will only return `true`
26
- * after `response.send()`, `response.view()`,
27
- * `response.sendFile()` or `response.download()` methods
28
- * call.
29
- *
30
- * @example
31
- * ```ts
32
- * if (response.sent) {
33
- * // do something
34
- * }
35
- * ```
36
- */
37
- get sent(): boolean;
38
- /**
39
- * Get the response body sent in response. Keep
40
- * in mind that this method will only return `true`
41
- * after `response.send()`, `response.view()`,
42
- * `response.sendFile()` or `response.download()` methods
43
- * call.
44
- *
45
- * @example
46
- * ```ts
47
- * const { createdAt, updatedAt } = response.body
48
- * ```
49
- */
50
- get body(): any | any[];
51
- /**
52
- * Get the status code sent in response. Keep
53
- * in mind that this method will only return `true`
54
- * after `response.send()`, `response.view()`,
55
- * `response.sendFile()` or `response.download()` methods
56
- * call.
57
- *
58
- * @example
59
- * ```ts
60
- * if (response.statusCode !== 200) {
61
- * // do something
62
- * }
63
- * ```
64
- */
65
- get statusCode(): number;
66
- /**
67
- * Get the headers set in the response.
68
- *
69
- * @example
70
- * ```ts
71
- * const headers = response.headers
72
- * ```
73
- */
74
- get headers(): any;
75
- /**
76
- * Get the time in MS of how much the request has
77
- * taken to response. Keep in mind that this method
78
- * will only return `true` after `response.send()`,
79
- * `response.view()`, `response.sendFile()` or
80
- * `response.download()` methods call.
81
- *
82
- * @example
83
- * ```ts
84
- * console.log(response.responseTime) // 1000
85
- * ```
86
- */
87
- get responseTime(): number;
88
- /**
89
- * Terminate the request sending a view to be rendered.
90
- *
91
- * @example
92
- * ```ts
93
- * return response.view('welcome', { name: 'lenon' })
94
- * ```
95
- */
96
- view(view: string, data?: any): Promise<Response>;
97
- /**
98
- * Terminate the request sending the response body or not.
99
- *
100
- * @example
101
- * ```ts
102
- * return response.send({ name: 'lenon' })
103
- * ```
104
- */
105
- send(data?: any): Promise<Response>;
106
- /**
107
- * @example
108
- * ```ts
109
- * return response.sendFile('img.png')
110
- * ```
111
- */
112
- sendFile(filename: string, filepath?: string): Promise<Response>;
113
- /**
114
- * @example
115
- * ```ts
116
- * return response.sendFile('img.png', { cacheControl: false })
117
- * ```
118
- */
119
- sendFile(filename: string, options?: string | SendOptions): Promise<Response>;
120
- /**
121
- * @example
122
- * ```ts
123
- * return response.sendFile('img.png', Path.tmp(), {
124
- * cacheControl: false
125
- * })
126
- * ```
127
- */
128
- sendFile(filename: string, filepath?: string, options?: SendOptions): Promise<Response>;
129
- /**
130
- * @example
131
- * ```ts
132
- * return response.download('img.png', 'custom-img.png')
133
- * ```
134
- */
135
- download(filepath: string, filename: string): Promise<Response>;
136
- /**
137
- * @example
138
- * ```ts
139
- * return response.download('img.png', 'custom-img.png', {
140
- * cacheControl: false
141
- * })
142
- * ```
143
- */
144
- download(filepath: string, filename: string, options?: SendOptions): Promise<Response>;
145
- /**
146
- * Set the response status code.
147
- *
148
- * @example
149
- * ```ts
150
- * return response.status(200).send()
151
- * ```
152
- */
153
- status(code: number): Response;
154
- /**
155
- * Add some header to the response.
156
- *
157
- * @example
158
- * ```ts
159
- * response.header('content-type', 'application/json')
160
- *
161
- * return response.header('accept-encoding', 'gzip').send(user)
162
- * ```
163
- */
164
- header(header: string, value: any): Response;
165
- /**
166
- * Verify if response has some header.
167
- *
168
- * @example
169
- * ```ts
170
- * if (response.hasHeader('content-type')) {
171
- * // do something
172
- * }
173
- * ```
174
- */
175
- hasHeader(header: string): boolean;
176
- /**
177
- * Add some header safely to the response. This means that
178
- * the header is not going to be added if is already set.
179
- *
180
- * @example
181
- * ```ts
182
- * response.safeHeader('content-type', 'application/json')
183
- * ```
184
- */
185
- safeHeader(header: string, value: any): Response;
186
- /**
187
- * Remove some header from the response.
188
- *
189
- * @example
190
- * ```ts
191
- * response.removeHeader('content-type')
192
- * ```
193
- */
194
- removeHeader(header: string): Response;
195
- /**
196
- * Redirect the response to other url. You can also set a
197
- * different status code for the redirect.
198
- *
199
- * @example
200
- * ```ts
201
- * return response.redirect('users', 304)
202
- * ```
203
- */
204
- redirectTo(url: string, status?: number): Promise<Response>;
205
- /**
206
- * Apply helmet in response.
207
- *
208
- * @example
209
- * ```ts
210
- * return response
211
- * .helmet({ enableCSPNonces: false })
212
- * .view('profile', user)
213
- * ```
214
- */
215
- helmet(options: FastifyHelmetOptions): Response;
216
- }
10
+ import type { Request, Response } from '#src/types';
11
+ /**
12
+ * Create the Athenna response object
13
+ */
14
+ export declare function response(reply: FastifyReply, request?: Request): Response;
@@ -7,230 +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. Keep
17
- * in mind that this method will only return `true`
18
- * after `response.send()`, `response.view()`,
19
- * `response.sendFile()` or `response.download()` methods
20
- * call.
21
- *
22
- * @example
23
- * ```ts
24
- * if (response.sent) {
25
- * // do something
26
- * }
27
- * ```
28
- */
29
- get sent() {
30
- return this.response.sent;
31
- }
32
- /**
33
- * Get the response body sent in response. Keep
34
- * in mind that this method will only return `true`
35
- * after `response.send()`, `response.view()`,
36
- * `response.sendFile()` or `response.download()` methods
37
- * call.
38
- *
39
- * @example
40
- * ```ts
41
- * const { createdAt, updatedAt } = response.body
42
- * ```
43
- */
44
- get body() {
45
- return this.response.body;
46
- }
47
- /**
48
- * Get the status code sent in response. Keep
49
- * in mind that this method will only return `true`
50
- * after `response.send()`, `response.view()`,
51
- * `response.sendFile()` or `response.download()` methods
52
- * call.
53
- *
54
- * @example
55
- * ```ts
56
- * if (response.statusCode !== 200) {
57
- * // do something
58
- * }
59
- * ```
60
- */
61
- get statusCode() {
62
- return this.response.statusCode;
63
- }
64
- /**
65
- * Get the headers set in the response.
66
- *
67
- * @example
68
- * ```ts
69
- * const headers = response.headers
70
- * ```
71
- */
72
- get headers() {
73
- return this.response.getHeaders();
74
- }
75
- /**
76
- * Get the time in MS of how much the request has
77
- * taken to response. Keep in mind that this method
78
- * will only return `true` after `response.send()`,
79
- * `response.view()`, `response.sendFile()` or
80
- * `response.download()` methods call.
81
- *
82
- * @example
83
- * ```ts
84
- * console.log(response.responseTime) // 1000
85
- * ```
86
- */
87
- get responseTime() {
88
- return this.response.elapsedTime;
89
- }
90
- /**
91
- * Terminate the request sending a view to be rendered.
92
- *
93
- * @example
94
- * ```ts
95
- * return response.view('welcome', { name: 'lenon' })
96
- * ```
97
- */
98
- async view(view, data) {
99
- const content = await View.render(view, { ...data, request: this.request });
100
- await this.safeHeader('Content-Type', 'text/html; charset=utf-8').response.send(content);
101
- this.response.body = content;
102
- return this;
103
- }
104
- /**
105
- * Terminate the request sending the response body or not.
106
- *
107
- * @example
108
- * ```ts
109
- * return response.send({ name: 'lenon' })
110
- * ```
111
- */
112
- async send(data) {
113
- await this.response.send(data);
114
- this.response.body = data;
115
- return this;
116
- }
117
- /**
118
- * Terminate the request sending a file.
119
- *
120
- * @example
121
- * ```ts
122
- * return response.sendFile('img.png')
123
- * ```
124
- */
125
- async sendFile(filename, filepath, options) {
126
- await this.response.sendFile(filename, filepath, options);
127
- return this;
128
- }
129
- /**
130
- * Terminate the request sending a file with custom name.
131
- *
132
- * @example
133
- * ```ts
134
- * return response.download('img.png', 'custom-img.png')
135
- * ```
136
- */
137
- async download(filepath, filename, options) {
138
- await this.response.download(filename, filepath, options);
139
- return this;
140
- }
141
- /**
142
- * Set the response status code.
143
- *
144
- * @example
145
- * ```ts
146
- * return response.status(200).send()
147
- * ```
148
- */
149
- status(code) {
150
- this.response.status(code);
151
- return this;
152
- }
153
- /**
154
- * Add some header to the response.
155
- *
156
- * @example
157
- * ```ts
158
- * response.header('content-type', 'application/json')
159
- *
160
- * return response.header('accept-encoding', 'gzip').send(user)
161
- * ```
162
- */
163
- header(header, value) {
164
- this.response.header(header, value);
165
- return this;
166
- }
167
- /**
168
- * Verify if response has some header.
169
- *
170
- * @example
171
- * ```ts
172
- * if (response.hasHeader('content-type')) {
173
- * // do something
174
- * }
175
- * ```
176
- */
177
- hasHeader(header) {
178
- return this.response.hasHeader(header);
179
- }
180
- /**
181
- * Add some header safely to the response. This means that
182
- * the header is not going to be added if is already set.
183
- *
184
- * @example
185
- * ```ts
186
- * response.safeHeader('content-type', 'application/json')
187
- * ```
188
- */
189
- safeHeader(header, value) {
190
- this.response.header(header, value);
191
- return this;
192
- }
193
- /**
194
- * Remove some header from the response.
195
- *
196
- * @example
197
- * ```ts
198
- * response.removeHeader('content-type')
199
- * ```
200
- */
201
- removeHeader(header) {
202
- this.response.removeHeader(header);
203
- return this;
204
- }
205
- /**
206
- * Redirect the response to other url. You can also set a
207
- * different status code for the redirect.
208
- *
209
- * @example
210
- * ```ts
211
- * return response.redirect('users', 304)
212
- * ```
213
- */
214
- async redirectTo(url, status) {
215
- if (status) {
216
- await this.response.redirect(status, url);
217
- 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;
218
86
  }
219
- await this.response.redirect(url);
220
- return this;
221
- }
222
- /**
223
- * Apply helmet in response.
224
- *
225
- * @example
226
- * ```ts
227
- * return response
228
- * .helmet({ enableCSPNonces: false })
229
- * .view('profile', user)
230
- * ```
231
- */
232
- helmet(options) {
233
- this.response.helmet(options);
234
- return this;
235
- }
87
+ };
88
+ return response;
236
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
@@ -19,9 +19,11 @@ export class FastifyHandler {
19
19
  if (!req.data) {
20
20
  req.data = {};
21
21
  }
22
- const request = new Request(req);
23
- const response = new Response(res, request);
24
- return handler({ request, response, data: req.data });
22
+ const ctx = {};
23
+ ctx.data = req.data;
24
+ ctx.request = request(req);
25
+ ctx.response = response(res, ctx.request);
26
+ return handler(ctx);
25
27
  };
26
28
  }
27
29
  /**
@@ -38,19 +40,17 @@ export class FastifyHandler {
38
40
  if (!req.data) {
39
41
  req.data = {};
40
42
  }
41
- const request = new Request(req);
42
- const response = new Response(res, request);
43
43
  if (Is.Json(payload)) {
44
44
  payload = JSON.parse(payload);
45
45
  }
46
46
  res.body = payload;
47
- payload = await handler({
48
- request,
49
- response,
50
- status: response.statusCode,
51
- data: req.data
52
- });
53
- 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;
54
54
  if (Is.Object(payload)) {
55
55
  payload = JSON.stringify(payload);
56
56
  }
@@ -65,15 +65,13 @@ export class FastifyHandler {
65
65
  if (!req.data) {
66
66
  req.data = {};
67
67
  }
68
- const request = new Request(req);
69
- const response = new Response(res, request);
70
- await handler({
71
- request,
72
- response,
73
- data: req.data,
74
- status: res.statusCode,
75
- responseTime: res.elapsedTime
76
- });
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);
77
75
  };
78
76
  }
79
77
  /**
@@ -84,14 +82,12 @@ export class FastifyHandler {
84
82
  if (!req.data) {
85
83
  req.data = {};
86
84
  }
87
- const request = new Request(req);
88
- const response = new Response(res, request);
89
- await handler({
90
- request,
91
- response,
92
- data: req.data,
93
- error
94
- });
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);
95
91
  };
96
92
  }
97
93
  }
@@ -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
  */