Skip to content

Instantly share code, notes, and snippets.

@webjay
Created December 13, 2022 19:03

Revisions

  1. webjay created this gist Dec 13, 2022.
    65 changes: 65 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,65 @@
    import { NextApiRequest } from 'next';

    // Inspired by https://github.com/myshenin/aws-lambda-multipart-parser

    export interface FilePart {
    type: string
    filename: string
    contentType: string
    content: unknown
    }

    interface Part {
    [name: string]: FilePart | string
    }

    function getBoundary({ headers: { 'content-type': contentType } }: NextApiRequest) {
    return contentType?.toLowerCase().split('boundary=')[1].trim()
    }

    function itemMatch(item: string, re: RegExp) {
    const match = re.exec(item)
    if (match === null) {
    return ''
    }
    return match[1]
    }

    function getContent(item: string) {
    if (/filename=".+"/g.test(item)) {
    const key = itemMatch(item, /name="(.+)";/g)
    const value = {
    type: 'file',
    filename: itemMatch(item, /filename="(.+)"/g),
    contentType: itemMatch(item, /Content-Type:\s(.+)/g),
    content: item.slice(
    item.search(/Content-Type:\s.+/g) +
    itemMatch(item, /(Content-Type:\s.+)/g).length + 4,
    -4
    ),
    }
    return { [key]: value }
    } else if (/name=".+"/g.test(item)) {
    const key = itemMatch(item, /name="(.+)"/g)
    const value = item.slice(
    item.search(/name=".+"/g) + itemMatch(item, /(name=".+")/g).length + 4,
    -4
    )
    return { [key]: value }
    }
    }

    export function multiParse(req: NextApiRequest) {
    const boundary = getBoundary(req)
    if (!boundary) {
    return null
    }
    const fields: string[] = req.body?.split(boundary)
    if (!fields) {
    return null
    }
    return fields.reduce((result, item) => ({
    ...result,
    ...getContent(item)
    }), {} as Part)
    }