You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
5.2 KiB
178 lines
5.2 KiB
3 years ago
|
import fastify from 'fastify'
|
||
|
import fastifyMultipart from '..'
|
||
|
import { Multipart, MultipartFields, MultipartFile } from '..'
|
||
|
import * as util from 'util'
|
||
|
import { pipeline, Readable } from 'stream'
|
||
|
import * as fs from 'fs'
|
||
|
import { expectError, expectType } from 'tsd'
|
||
|
import { FastifyErrorConstructor } from "fastify-error"
|
||
|
import { BusboyConfig, BusboyFileStream } from "@fastify/busboy";
|
||
|
|
||
|
const pump = util.promisify(pipeline)
|
||
|
|
||
|
const runServer = async () => {
|
||
|
const app = fastify()
|
||
|
|
||
|
app.register(fastifyMultipart, {
|
||
|
addToBody: true,
|
||
|
sharedSchemaId: 'sharedId',
|
||
|
throwFileSizeLimit: false,
|
||
|
// stream should be of type streams.Readable
|
||
|
// body should be of type fastifyMulipart.Record<string, BodyEntry>
|
||
|
onFile: (fieldName: string, stream: any, filename: string, encoding: string, mimetype: string, body: Record<string, any>) => {
|
||
|
console.log(fieldName, stream, filename, encoding, mimetype, body)
|
||
|
},
|
||
|
limits: {
|
||
|
fieldNameSize: 200,
|
||
|
fieldSize: 200,
|
||
|
fields: 200,
|
||
|
fileSize: 200,
|
||
|
files: 2,
|
||
|
headerPairs: 200
|
||
|
}
|
||
|
})
|
||
|
|
||
|
app.register(fastifyMultipart, {
|
||
|
attachFieldsToBody: true,
|
||
|
onFile: (part: MultipartFile) => {
|
||
|
console.log(part)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
app.get('/path', (request) => {
|
||
|
const isMultiPart = request.isMultipart()
|
||
|
request.multipart((field, file, filename, encoding, mimetype) => {
|
||
|
console.log(field, file, filename, encoding, mimetype, isMultiPart)
|
||
|
}, (err) => {
|
||
|
throw err
|
||
|
}, {
|
||
|
limits: {
|
||
|
fileSize: 10000
|
||
|
}
|
||
|
})
|
||
|
})
|
||
|
|
||
|
// usage
|
||
|
app.post('/', async (req, reply) => {
|
||
|
const data = await req.file()
|
||
|
|
||
|
expectType<BusboyFileStream>(data.file)
|
||
|
expectType<boolean>(data.file.truncated)
|
||
|
expectType<MultipartFields>(data.fields)
|
||
|
expectType<string>(data.fieldname)
|
||
|
expectType<string>(data.filename)
|
||
|
expectType<string>(data.encoding)
|
||
|
expectType<string>(data.mimetype)
|
||
|
|
||
|
await pump(data.file, fs.createWriteStream(data.filename))
|
||
|
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// Multiple fields including scalar values
|
||
|
app.post<{Body: {file: Multipart, foo: Multipart<string>}}>('/upload/stringvalue', async (req, reply) => {
|
||
|
expectError(req.body.foo.file);
|
||
|
expectType<string>(req.body.foo.value);
|
||
|
|
||
|
expectType<BusboyFileStream>(req.body.file.file)
|
||
|
expectError(req.body.file.value);
|
||
|
reply.send();
|
||
|
})
|
||
|
|
||
|
app.post<{Body: {file: Multipart, num: Multipart<number>}}>('/upload/stringvalue', async (req, reply) => {
|
||
|
expectType<number>(req.body.num.value);
|
||
|
reply.send();
|
||
|
|
||
|
// file is a file
|
||
|
expectType<BusboyFileStream>(req.body.file.file)
|
||
|
expectError(req.body.file.value);
|
||
|
})
|
||
|
|
||
|
// busboy
|
||
|
app.post('/', async function (req, reply) {
|
||
|
const options: Partial<BusboyConfig> = { limits: { fileSize: 1000 } };
|
||
|
const data = await req.file(options)
|
||
|
await pump(data.file, fs.createWriteStream(data.filename))
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// handle multiple file streams
|
||
|
app.post('/', async (req, reply) => {
|
||
|
const parts = req.files()
|
||
|
for await (const part of parts) {
|
||
|
await pump(part.file, fs.createWriteStream(part.filename))
|
||
|
}
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// handle multiple file streams and fields
|
||
|
app.post('/upload/raw/any', async function (req, reply) {
|
||
|
const parts = req.parts()
|
||
|
for await (const part of parts) {
|
||
|
if (part.file) {
|
||
|
await pump(part.file, fs.createWriteStream(part.filename))
|
||
|
} else {
|
||
|
console.log(part)
|
||
|
}
|
||
|
}
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// accumulate whole file in memory
|
||
|
app.post('/upload/raw/any', async function (req, reply) {
|
||
|
const data = await req.file()
|
||
|
const buffer = await data.toBuffer()
|
||
|
// upload to S3
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// upload files to disk and work with temporary file paths
|
||
|
app.post('/upload/files', async function (req, reply) {
|
||
|
// stores files to tmp dir and return files
|
||
|
const files = await req.saveRequestFiles()
|
||
|
files[0].filepath
|
||
|
files[0].fieldname
|
||
|
files[0].filename
|
||
|
files[0].encoding
|
||
|
files[0].mimetype
|
||
|
files[0].fields // other parsed parts
|
||
|
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// upload files to disk with busboy options
|
||
|
app.post('/upload/files', async function (req, reply) {
|
||
|
const options: Partial<BusboyConfig> = { limits: { fileSize: 1000 } };
|
||
|
await req.saveRequestFiles(options)
|
||
|
|
||
|
reply.send()
|
||
|
})
|
||
|
|
||
|
// access all errors
|
||
|
app.post('/upload/files', async function (req, reply) {
|
||
|
const { FilesLimitError } = app.multipartErrors
|
||
|
|
||
|
expectType<FastifyErrorConstructor>(app.multipartErrors.FieldsLimitError);
|
||
|
expectType<FastifyErrorConstructor>(app.multipartErrors.FilesLimitError);
|
||
|
expectType<FastifyErrorConstructor>(app.multipartErrors.InvalidMultipartContentTypeError);
|
||
|
expectType<FastifyErrorConstructor>(app.multipartErrors.PartsLimitError);
|
||
|
expectType<FastifyErrorConstructor>(app.multipartErrors.PrototypeViolationError);
|
||
|
expectType<FastifyErrorConstructor>(app.multipartErrors.RequestFileTooLargeError);
|
||
|
|
||
|
// test instanceof Error
|
||
|
const a = new FilesLimitError();
|
||
|
if (a instanceof FilesLimitError) {
|
||
|
console.log("FilesLimitError occurred.");
|
||
|
}
|
||
|
|
||
|
reply.send();
|
||
|
})
|
||
|
|
||
|
await app.ready()
|
||
|
}
|
||
|
|
||
|
runServer().then(
|
||
|
console.log.bind(console, 'Success'),
|
||
|
console.error.bind(console, 'Error')
|
||
|
)
|