Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: group parser #1

Merged
merged 1 commit into from
Jul 11, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 50 additions & 49 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Ajv } from 'ajv'
import { FastifyPluginAsync, FastifyRequest } from 'fastify'
import FastifyPlugin from 'fastify-plugin'
import { Fields, File, Files, IncomingForm, Options } from 'formidable'
import Formidable from 'formidable/Formidable'
import { IncomingMessage } from 'http'
const kIsMultipart = Symbol.for('[isMultipart]')

declare module 'fastify' {
Expand All @@ -19,6 +21,37 @@ export interface FastifyFormidableOptions {
formidable?: Options
}

function promisify (func: Function): (request: IncomingMessage) => Promise<{ fields: Fields, files: Files }> {
return async function (request: IncomingMessage): Promise<{ fields: Fields, files: Files }> {
return await new Promise(function (resolve, reject) {
func(request, function (err: any, fields: Fields, files: Files) {
if (err as true) reject(err)
resolve({ fields, files })
})
})
}
}

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 }> {
const { fields, files } = await parse(request.raw)

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
})
}

return { body, files }
}
}

const plugin: FastifyPluginAsync<FastifyFormidableOptions> = async function (fastify, options) {
const formidable = new IncomingForm(options.formidable)

Expand All @@ -35,47 +68,25 @@ const plugin: FastifyPluginAsync<FastifyFormidableOptions> = async function (fas
requestFormidable = new IncomingForm(decoratorOptions)
}

return await new Promise(function (resolve, reject) {
// skip if it is not multipart
if (!request[kIsMultipart]) return reject(new Error('Cannot handle non-multipart request'))
requestFormidable.parse(request.raw, function (err, fields, files) {
if (err as true) reject(err)
request.body = Object.assign({}, fields)
if (options.removeFilesFromBody !== true) {
Object.keys(files).forEach(function (key) {
(request.body as any)[key] = Array.isArray(files[key])
? (files[key] as File[]).map(function (file) {
return file.path
})
: (files[key] as File).path
})
}
request.files = files
resolve(request.body)
})
})
const parser = buildRequestParser(requestFormidable)
const { body, files } = await parser(request, { removeFilesFromBody: options.removeFilesFromBody })
request.body = body
request.files = files

return body
})

if (options.addContentTypeParser === true && options.addHooks === true) {
throw new Error('Cannot enable `addContentTypeParser` togather with `addHooks`')
}

if (options.addContentTypeParser === true) {
fastify.addContentTypeParser('multipart', function (request, _, done) {
fastify.addContentTypeParser('multipart', async function (request: FastifyRequest) {
request[kIsMultipart] = true
formidable.parse(request.raw, function (err, fields, files) {
if (err as true) done(err)
const body = Object.assign({}, fields)
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
})
request.files = files
done(null, body)
})
const parse = buildRequestParser(formidable)
const { body, files } = await parse(request)
request.files = files
return body
})
} else {
fastify.addContentTypeParser('multipart', function (request, _, done) {
Expand All @@ -85,23 +96,13 @@ const plugin: FastifyPluginAsync<FastifyFormidableOptions> = async function (fas
}

if (options.addHooks === true) {
fastify.addHook('preValidation', function (request, reply, done) {
fastify.addHook('preValidation', async function (request: FastifyRequest) {
// skip if it is not multipart
if (!request[kIsMultipart]) return done()

formidable.parse(request.raw, function (err, fields, files) {
if (err as true) done(err)
request.body = Object.assign({}, fields)
Object.keys(files).forEach(function (key) {
(request.body as any)[key] = Array.isArray(files[key])
? (files[key] as File[]).map(function (file) {
return file.path
})
: (files[key] as File).path
})
request.files = files
done()
})
if (!request[kIsMultipart]) return
const parse = buildRequestParser(formidable)
const { body, files } = await parse(request)
request.body = body
request.files = files
})
}

Expand Down