feathersjs / feathers

The API and real-time application framework
https://feathersjs.com
MIT License
15.03k stars 748 forks source link

fix(koa): Replace koa-bodyparser with koa-body #3093

Closed 8BallBomBom closed 1 year ago

8BallBomBom commented 1 year ago

Been looking at possible ways to implement an upload service.

After looking over the current options it would appear either we use koa-body to allow handling of multipart/form-data or we roll the dice and find another package as koa-bodyparser doesn't support multipart/form-data.

There is also the option where each developer could import and use koa-body themselves. But there is currently a type compatibility issue with the older koa-bodyparser package. More info over here.

What i can say though is it seems koa-body functions as a more up to date feature full drop in replacement. Might need some extra testing though.

caiqueacct commented 11 months ago

Is possible to create a sample how to upload a file using koa-body? I can see the file being saved on the OS but I don't know how to get the filename saved using the context. This is how I configured:

app.use(
  bodyParser({
    multipart: true,
    jsonLimit: '10mb',
    formidable: {
      uploadDir: bucketUpload.upload
    }
  })
)

Thanks

8BallBomBom commented 11 months ago

The way i'm handling this currently is by using the koa before hook in a service, check this. ctx.request.files will return an array of files you're uploading.

As for the right way to implement things, that is a good question, currently i'm rocking a janky implementation of @koa/router to make sure only set routes allow uploads... otherwise every route will accept an upload. Not really sure about the best method of implementation as of yet.

caiqueacct commented 11 months ago

Thanks. That's what I ended up using too. This is the code that I'm using although I also don't know if it's the best implementation but it's working like charm.

async (ctx, next) => {
  const readableStream = await getObjectStorage(
    objectStorage,
    result.objectName
  );
  const res = ctx.res;
  ctx.response.attachment(result.originalFilename, { type: "inline" });

  await new Promise((resolve, reject) => {
    const writableStream = new WritableStream({
      write(chunk) {
        try {
          res.write(chunk);
        } catch (e) {
          console.error("Error writing ", e);
        }
      },
    });

    readableStream
      .pipeTo(writableStream)
      .then(() => {
        res.end();
        resolve("SUCCESS");
      })
      .catch((e) => {
        console.error("Erro", e);
        reject(e.message);
      });
  });
};
8BallBomBom commented 11 months ago

Thanks for sharing, if i find a better way to handle things then i'll probably contribute towards the docs 👍🏻