redwoodjs / redwood

The App Framework for Startups
https://redwoodjs.com
MIT License
16.93k stars 973 forks source link

[Bug?]: Uploading files through custom functions doesn't work #10461

Open c-ciobanu opened 2 months ago

c-ciobanu commented 2 months ago

What's not working?

Uploading files using a custom function and fastify doesn't seem to work. There was some discussion on the forum https://community.redwoodjs.com/t/uploading-files-using-redwood-function-and-fastify/5814/8 but there was no solution there so I'm opening an issue for it.

The Problem:

I am trying to create a custom function to upload files but it's not working. I'm calling my custom function like this:

const formData = new FormData()
formData.append('file', blob)

await fetch('/.redwood/functions/uploadDocs', {
  method: 'POST',
  body: formData,
})

and getting the following response:

{
    "statusCode": 400,
    "code": "FST_ERR_CTP_INVALID_CONTENT_LENGTH",
    "error": "Bad Request",
    "message": "Request body size did not match Content-Length"
}

There seems to be a discrepancy on how the request body size is calculated on the server and the Content-Length header that is automatically calculated by the browser.

What I tried doing to make it work: By looking around I discovered that if I comment out this code in the api-server package https://github.com/redwoodjs/redwood/blob/605545e81b28e7e83a5f3d04464ad46847605293/packages/api-server/src/plugins/api.ts#L41-L45 and change it with:

fastify.addContentTypeParser(
  ['application/x-www-form-urlencoded', 'multipart/form-data'],
  function (req, payload, done) {
    done(null, req)
  }
)

the fetch will not fail anymore but I couldn't access the request body in the custom function probably because the content parser is not configured properly.

Another interesting thing is that if instead of changing the code in the api-server package I only comment it out and then add

fastify.addContentTypeParser(
  ['application/x-www-form-urlencoded', 'multipart/form-data'],
  function (req, payload, done) {
    done(null, req)
  }
)

to my api/src/server.ts the fetch will still not work. Might be something to look into, it would be strange if the addContentTypeParser added in api/src/server.ts would not be applied.

Another option I tried was installing @fastify/multipart and then registering it in my api/src/server.ts as server.register(multipart) but with no success at all.

How do we reproduce the bug?

Create a simple custom function

// api/src/functions/uploadDocs/uploadDocs.ts
export const handler = async (event: APIGatewayEvent, _context: Context) => {
  logger.info(`${event.httpMethod} ${event.path}: uploadDocs function`)

  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      data: 'uploadDocs function',
    }),
  }
}

On the frontend call the function as such and check the network tab to see the error message

const formData = new FormData()
formData.append('file', blob)

await fetch('/.redwood/functions/uploadDocs', {
  method: 'POST',
  body: formData,
})

What's your environment? (If it applies)

No response

Are you interested in working on this?

ahaywood commented 2 months ago

@c-ciobanu Thanks for taking the time to file this issue. I'm going to tag in another core team member to see if they can help resolve this.

Josh-Walker-GM commented 3 weeks ago

Hey @c-ciobanu sorry for taking so long for someone to get back to you.

We did indeed have a bug where you weren't able to customise the api server file as the docs suggested you could. We have fixed this although it's not yet out in a published release. It should be out this week. The updated documentation is already available via the canary docs: https://redwoodjs.com/docs/canary/docker#configuring-the-server

I think this would resolve your issue. It would be great to cycle back to this one once the new version is released to confirm it does indeed fix it.