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