Skip to content

Commit 31008d3

Browse files
authored
Merge pull request #213 from AthennaIO/develop
feat: add @fastify/multipart
2 parents e323792 + c188695 commit 31008d3

File tree

5 files changed

+182
-12
lines changed

5 files changed

+182
-12
lines changed

package-lock.json

Lines changed: 51 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@athenna/http",
3-
"version": "5.27.0",
3+
"version": "5.28.0",
44
"description": "The Athenna Http server. Built on top of fastify.",
55
"license": "MIT",
66
"author": "João Lenon <lenon@athenna.io>",
@@ -85,6 +85,7 @@
8585
"@athenna/vite": "^5.13.0",
8686
"@fastify/cors": "^10.0.2",
8787
"@fastify/helmet": "^13.0.1",
88+
"@fastify/multipart": "^9.0.3",
8889
"@fastify/rate-limit": "^10.2.2",
8990
"@fastify/static": "^8.0.4",
9091
"@fastify/swagger": "^9.4.2",

src/context/Request.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@
77
* file that was distributed with this source code.
88
*/
99

10+
import type {
11+
SavedMultipartFile,
12+
FastifyMultipartBaseOptions
13+
} from '@fastify/multipart'
14+
1015
import type { AddressInfo } from 'node:net'
1116
import type { FastifyRequest } from 'fastify'
1217
import { Is, Json, Macroable } from '@athenna/common'
18+
import type { BusboyConfig } from '@fastify/busboy'
1319

1420
export class Request extends Macroable {
1521
/**
@@ -351,6 +357,69 @@ export class Request extends Macroable {
351357
return body
352358
}
353359

360+
/**
361+
* Check if the request is multipart.
362+
*/
363+
public isMultipart() {
364+
return this.request.isMultipart()
365+
}
366+
367+
/**
368+
* Get the form data from the request.
369+
*/
370+
public formData(): Promise<FormData> {
371+
return this.request.formData()
372+
}
373+
374+
/**
375+
* Get the parts from the request.
376+
*/
377+
public parts(options?: Omit<BusboyConfig, 'headers'>) {
378+
return this.request.parts(options)
379+
}
380+
381+
/**
382+
* Get the file from the request.
383+
*/
384+
public file(
385+
options?: Omit<BusboyConfig, 'headers'> | FastifyMultipartBaseOptions
386+
) {
387+
return this.request.file(options)
388+
}
389+
390+
/**
391+
* Get the files from the request.
392+
*/
393+
public files(
394+
options?: Omit<BusboyConfig, 'headers'> | FastifyMultipartBaseOptions
395+
) {
396+
return this.request.files(options)
397+
}
398+
399+
/**
400+
* Save the files from the request.
401+
*/
402+
public saveRequestFiles(
403+
options?: Omit<BusboyConfig, 'headers'> & { tmpdir?: string }
404+
) {
405+
return this.request.saveRequestFiles(options)
406+
}
407+
408+
/**
409+
* Clean the files from the request.
410+
*/
411+
public cleanRequestFiles() {
412+
return this.request.cleanRequestFiles()
413+
}
414+
415+
/**
416+
* This will get populated as soon as a call to `saveRequestFiles` gets resolved.
417+
* Avoiding any future duplicate work
418+
*/
419+
public get savedRequestFiles(): SavedMultipartFile[] | null {
420+
return this.request.savedRequestFiles
421+
}
422+
354423
/**
355424
* Get the original fastify request.
356425
*/

src/kernels/HttpKernel.ts

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,13 @@ import { Annotation, type ServiceMeta } from '@athenna/ioc'
1818
import { File, Path, Module, String } from '@athenna/common'
1919
import { HttpExceptionHandler } from '#src/handlers/HttpExceptionHandler'
2020

21-
const corsPlugin = await Module.safeImport('@fastify/cors')
22-
const helmetPlugin = await Module.safeImport('@fastify/helmet')
23-
const swaggerPlugin = await Module.safeImport('@fastify/swagger')
24-
const swaggerUiPlugin = await Module.safeImport('@fastify/swagger-ui')
25-
const rateLimitPlugin = await Module.safeImport('@fastify/rate-limit')
26-
const staticPlugin = await Module.safeImport('@fastify/static')
27-
const rTracerPlugin = await Module.safeImport('cls-rtracer')
28-
const vitePlugin = await Module.safeImport('@athenna/vite/plugins/fastify')
29-
3021
export class HttpKernel {
3122
/**
3223
* Register the @fastify/cors plugin in the Http server.
3324
*/
3425
public async registerCors(): Promise<void> {
26+
const corsPlugin = await Module.safeImport('@fastify/cors')
27+
3528
if (Config.is('http.cors.enabled', false)) {
3629
debug(
3730
'Not able to register cors plugin. Set the http.cors.enabled configuration as true.'
@@ -53,6 +46,8 @@ export class HttpKernel {
5346
* Register the @fastify/helmet plugin in the Http server.
5447
*/
5548
public async registerHelmet(): Promise<void> {
49+
const helmetPlugin = await Module.safeImport('@fastify/helmet')
50+
5651
if (Config.is('http.helmet.enabled', false)) {
5752
debug(
5853
'Not able to register helmet plugin. Set the http.helmet.enabled configuration as true.'
@@ -76,6 +71,9 @@ export class HttpKernel {
7671
* Register the @fastify/swagger plugin in the Http server.
7772
*/
7873
public async registerSwagger(): Promise<void> {
74+
const swaggerPlugin = await Module.safeImport('@fastify/swagger')
75+
const swaggerUiPlugin = await Module.safeImport('@fastify/swagger-ui')
76+
7977
if (Config.is('http.swagger.enabled', false)) {
8078
debug(
8179
'Not able to register swagger plugin. Set the http.swagger.enabled configuration as true.'
@@ -129,6 +127,8 @@ export class HttpKernel {
129127
* Register the @fastify/rate-limit plugin in the Http server.
130128
*/
131129
public async registerRateLimit(): Promise<void> {
130+
const rateLimitPlugin = await Module.safeImport('@fastify/rate-limit')
131+
132132
if (Config.is('http.rateLimit.enabled', false)) {
133133
debug(
134134
'Not able to register rate limit plugin. Set the http.rateLimit.enabled configuration as true.'
@@ -152,6 +152,8 @@ export class HttpKernel {
152152
* Register the @fastify/static plugin in the Http server.
153153
*/
154154
public async registerStatic(): Promise<void> {
155+
const staticPlugin = await Module.safeImport('@fastify/static')
156+
155157
if (Config.is('http.static.enabled', false)) {
156158
debug(
157159
'Not able to register static plugin. Set the http.static.enabled configuration as true.'
@@ -175,6 +177,8 @@ export class HttpKernel {
175177
* Register the cls-rtracer plugin in the Http server.
176178
*/
177179
public async registerRTracer(trace?: boolean): Promise<void> {
180+
const rTracerPlugin = await Module.safeImport('cls-rtracer')
181+
178182
if (trace === false) {
179183
debug(
180184
'Not able to register rTracer plugin. Set the trace option as true in your http server options.'
@@ -209,6 +213,8 @@ export class HttpKernel {
209213
* Register the @athenna/vite plugin in the Http server.
210214
*/
211215
public async registerVite(trace?: boolean): Promise<void> {
216+
const vitePlugin = await Module.safeImport('@athenna/vite/plugins/fastify')
217+
212218
if (trace === false) {
213219
debug(
214220
'Not able to register vite plugin. Set the trace option as true in your http server options.'
@@ -234,6 +240,31 @@ export class HttpKernel {
234240
await Server.plugin(vitePlugin, this.getConfig('http.vite'))
235241
}
236242

243+
/**
244+
* Register the @fastify/multipart plugin in the Http server.
245+
*/
246+
public async registerMultipart(): Promise<void> {
247+
const multipartPlugin = await Module.safeImport('@fastify/multipart')
248+
249+
if (Config.is('http.multipart.enabled', false)) {
250+
debug(
251+
'Not able to register multipart plugin. Set the http.multipart.enabled configuration as true.'
252+
)
253+
254+
return
255+
}
256+
257+
if (!multipartPlugin) {
258+
debug(
259+
'Not able to register multipart plugin. Install @fastify/multipart package.'
260+
)
261+
262+
return
263+
}
264+
265+
await Server.plugin(multipartPlugin, this.getConfig('http.multipart'))
266+
}
267+
237268
/**
238269
* Register the global log terminator in the Http server.
239270
*/

tests/unit/kernels/HttpKernelTest.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ export default class HttpKernelTest {
6161
assert.isTrue(Server.fastify.hasPlugin('@fastify/helmet'))
6262
}
6363

64+
@Test()
65+
public async shouldBeAbleToRegisterTheFastifyMultipartPluginInTheHttpServer({ assert }: Context) {
66+
const kernel = new HttpKernel()
67+
await kernel.registerMultipart()
68+
69+
assert.isTrue(Server.fastify.hasPlugin('@fastify/multipart'))
70+
}
71+
6472
@Test()
6573
public async shouldBeAbleToRegisterTheFastifySwaggerPluginInTheHttpServer({ assert }: Context) {
6674
const kernel = new HttpKernel()
@@ -178,6 +186,18 @@ export default class HttpKernelTest {
178186
assert.isFalse(Server.fastify.hasPlugin('@fastify/helmet'))
179187
}
180188

189+
@Test()
190+
@Cleanup(() => Config.set('http.multipart.enabled', true))
191+
public async shouldNotRegisterTheFastifyMultipartPluginIfTheConfigurationIsDisabled({ assert }: Context) {
192+
Config.set('http.multipart.enabled', false)
193+
194+
const { HttpKernel } = await import(`../../../src/kernels/HttpKernel.js?v=${Math.random()}`)
195+
const kernel = new HttpKernel()
196+
await kernel.registerMultipart()
197+
198+
assert.isFalse(Server.fastify.hasPlugin('@fastify/multipart'))
199+
}
200+
181201
@Test()
182202
public async shouldNotRegisterTheFastifySwaggerPluginIfThePackageIsNotInstalled({ assert }: Context) {
183203
Mock.when(Module, 'safeImport').resolve(null)

0 commit comments

Comments
 (0)