Skip to content

Commit

Permalink
feat: auto create upload dir (#16)
Browse files Browse the repository at this point in the history
* feat: auto create upload dir

* chore: explain more on symbols
  • Loading branch information
climba03003 authored Aug 19, 2021
1 parent f39b8bf commit 8c15d5b
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 12 deletions.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ yarn add fastify-formidable
## Usage

```ts
import FastifyFormidable from 'fastify-formidable'
import FastifyFormidable, { kFileSavedPaths, kFileSavedPaths, kIsMultipartParsed } from 'fastify-formidable'

fastify.register(FastifyFormidable)

Expand All @@ -35,6 +35,15 @@ fastify.post('/', async function(request, reply) {
// access body
// note that file fields will exist in body and it will becomes the file path saved on disk
request.body

// access all the files path
request[kFileSavedPaths]

// check if it is multipart
if( request[kIsMultipart] === true ) {}

// check if it is already parsed
if ( request[kIsMultipartParsed] === true ) {}
})

// add content type parser which will automatic parse all `multipart/form-data` found
Expand All @@ -59,7 +68,9 @@ import FastifyFormidable from 'fastify-formidable'

fastify.register(FastifyFormidable, {
formidable: {
maxFileSize: 1000
maxFileSize: 1000,
// this folder will be automatic created by this plugin
uploadDir: '/'
}
})
```
Expand Down
38 changes: 28 additions & 10 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import { FastifyPluginAsync, FastifyRequest } from 'fastify'
import FastifyPlugin from 'fastify-plugin'
import { Fields, File, Files, IncomingForm, Options } from 'formidable'
import Formidable from 'formidable/Formidable'
import * as fs from 'fs'
import { IncomingMessage } from 'http'
const kIsMultipart = Symbol.for('[isMultipart]')
export const kIsMultipart = Symbol.for('[FastifyMultipart.isMultipart]')
export const kIsMultipartParsed = Symbol.for('[FastifyMultipart.isMultipartParsed]')
export const kFileSavedPaths = Symbol.for('[FastifyMultipart.fileSavedPaths]')

declare module 'fastify' {
interface FastifyRequest {
files: Files | null
parseMultipart: <Payload = Fields>(this: FastifyRequest, options?: Options) => Promise<Payload>
[kIsMultipart]: boolean
[kIsMultipartParsed]: boolean
[kFileSavedPaths]: string[]
}
}

Expand All @@ -35,27 +40,40 @@ function promisify (func: Function): (request: IncomingMessage) => Promise<{ fie
function buildRequestParser (formidable: Formidable): (request: FastifyRequest, options?: Pick<FastifyFormidableOptions, 'removeFilesFromBody'>) => Promise<{ body: Fields, files: Files }> {
const parse = promisify(formidable.parse.bind(formidable))
return async function (request: FastifyRequest, options?: Pick<FastifyFormidableOptions, 'removeFilesFromBody'>): Promise<{ body: Fields, files: Files }> {
if (request[kIsMultipartParsed]) {
request.log.warn('multipart already parsed, you probably need to check your code why it is parsed twice.')
return { body: request.body as Fields, files: request.files as Files }
}
const { fields, files } = await parse(request.raw)
request[kFileSavedPaths] = []

const body = Object.assign({}, fields)
if (options?.removeFilesFromBody !== true) {
Object.keys(files).forEach(function (key) {
(body as any)[key] = Array.isArray(files[key])
? (files[key] as File[]).map(function (file) {
return file.path
})
: (files[key] as File).path
})
}
Object.keys(files).forEach(function (key) {
const paths = Array.isArray(files[key])
? (files[key] as File[]).map(function (file) {
return file.path
})
: (files[key] as File).path
if (options?.removeFilesFromBody !== true) (body as any)[key] = paths
request[kFileSavedPaths].push(...paths)
})

request[kIsMultipartParsed] = true
return { body, files }
}
}

const plugin: FastifyPluginAsync<FastifyFormidableOptions> = async function (fastify, options) {
// create upload folder when not exist
if (typeof options.formidable?.uploadDir === 'string') {
await fs.promises.mkdir(options.formidable.uploadDir, { recursive: true })
}

const formidable = new IncomingForm(options.formidable)

fastify.decorateRequest(kIsMultipart, false)
fastify.decorateRequest(kIsMultipartParsed, false)
fastify.decorateRequest(kFileSavedPaths, null)
fastify.decorateRequest('files', null)

fastify.decorateRequest('parseMultipart', async function (this: FastifyRequest, decoratorOptions?: Options) {
Expand Down
25 changes: 25 additions & 0 deletions test/uploadDir.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Fastify from 'fastify'
import * as fs from 'fs'
import * as path from 'path'
import FastifyFormidable from '../lib'

const uploadDir = path.resolve('tmp')

describe('uploadDir', function () {
test('create', async function () {
const fastify = Fastify()
await fastify.register(FastifyFormidable, {
formidable: {
uploadDir
}
})

const stat = await fs.promises.lstat(uploadDir)
expect(stat.isDirectory()).toStrictEqual(true)
})

afterEach(async function () {
// clean up
await fs.promises.rmdir(uploadDir)
})
})

0 comments on commit 8c15d5b

Please sign in to comment.