Search code examples
node.jsfastifyfastify-multipart

How to access the file path of uploaded files in fastify


When using a form to upload some files I can see in dev tools in the network inspector and specifically in the payload tab under form data, in view source.

Note the below includes the file name including the path twoItems/Screenshot... its this path twoItems I need to access in the API but can't.

Security? Err why do I want this? It's for a document management app, users cant be creating folders in the browser and then add the files. They need to drag and drop nested directories of files.

------WebKitFormBoundarydJ6knkAHgNW7SIF7
Content-Disposition: form-data; name="file"; filename="twoItems/Screenshot 2022-03-11 at 08.58.24.png"
Content-Type: image/png


------WebKitFormBoundarydJ6knkAHgNW7SIF7
Content-Disposition: form-data; name="file"; filename="twoItems/Screenshot 2022-03-11 at 08.58.08.png"
Content-Type: image/png

so in the API I have a standard fastify API running

mport Fastify, { FastifyInstance, RouteShorthandOptions } from "fastify";
import { Server, IncomingMessage, ServerResponse } from "http";

const fs = require("fs");
const util = require("util");
const { pipeline } = require("stream");
const pump = util.promisify(pipeline);

const fastify: FastifyInstance = Fastify({});
fastify.register(require("fastify-multipart"));
fastify.register(require("fastify-cors"), {
  methods: ["GET", "PUT", "POST"],
});

const dir = "./files";
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir);
}

fastify.post("/upload", async (req: any, reply) => {
  console.log(req);
  const parts = await req.files();
  for await (const part of parts) {
    console.log(part); //---------------- LOG BELOW
    await pump(part.file, fs.createWriteStream(`./files/${part.filename}`));
  }
  reply.send();
});

const start = async () => {
  try {
    await fastify.listen(3001);
    const address = fastify.server.address();
    const port = typeof address === "string" ? address : address?.port;
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};
start();

I can't find how to access the path of each item

when I log out part I get...

<ref *1> {
  fieldname: 'file',
  filename: 'Screenshot 2022-03-11 at 17.52.11.png',
  encoding: '7bit',
  mimetype: 'image/png',
  file: FileStream {
    _readableState: ReadableState {
      objectMode: false,
      highWaterMark: 16384,
      buffer: BufferList { head: [Object], tail: [Object], length: 4 },
      length: 208151,
      pipes: [],
      flowing: null,
      ended: false,
      endEmitted: false,
      reading: false,
      sync: false,
      needReadable: false,
      emittedReadable: false,
      readableListening: false,
      resumeScheduled: false,
      errorEmitted: false,
      emitClose: true,
      autoDestroy: true,
      destroyed: false,
      errored: null,
      closed: false,
      closeEmitted: false,
      defaultEncoding: 'utf8',
      awaitDrainWriters: null,
      multiAwaitDrain: false,
      readingMore: false,
      dataEmitted: false,
      decoder: null,
      encoding: null,
      [Symbol(kPaused)]: null
    },
    _events: [Object: null prototype] {
      end: [Function (anonymous)],
      limit: [Function (anonymous)]
    },
    _eventsCount: 2,
    _maxListeners: undefined,
    bytesRead: 208151,
    truncated: false,
    _read: [Function (anonymous)],
    [Symbol(kCapture)]: false
  },
  fields: { file: [ [Object], [Object], [Object], [Circular *1] ] },
  _buf: null,
  toBuffer: [AsyncFunction: toBuffer]
}

this is undefined...

console.log(part.path);

Solution

  • You need to set the busboy's option:

    fastify.register(require("fastify-multipart"), {
      preservePath: true
    });
    

    You can find all the options here: https://github.com/fastify/busboy#busboy-methods