So, I tested this and I’ve 2 options to offer:
- Continue using
multipart/form-data
:
Yes, you could continue using it, but with a catch. If you only need to upload a file with the form (and no other form fields), this would do the trick. In the above code, simply change it to Buffer.from(event.body, 'base64')
. I repeat, there should not be any other data except the file. Not multiple files either, just 1 file! If you need multiple files, you’d have to send each file to a different serverless function. You can use the same function, but you’d have to invoke it again for each file. For form fields, you could use FormData()
, but make sure that you exclude the file from it.
- Switch to
application/json
:
Yes, submitting a form with application/json
might seem weird, but it works. However, there’s some extra client-side work that’s required. You need to convert the file to base64
and add each form field separately to the JSON payload. You could do it programatically too, but yeah that’s the workflow. Here’s an example:
const form = document.forms.fileForm
form.onsubmit = event => {
event.preventDefault()
new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(form.elements.file.files[0])
reader.onload = () => resolve(reader.result)
reader.onerror = error => reject(error)
}).then(file => {
fetch('/.netlify/functions/getData/', {
body: JSON.stringify({
file: file,
name: form.elements.name.value
}),
headers: {
'content-type': 'application/json'
},
method: 'post',
}).then(response => {
if (response.ok) {
return response.json()
} else {
throw response.statusText
}
}).then(data => {
console.log(data)
}).catch(error => {
console.log(error)
})
})
}
Finally, in the serverless function, no need to use Busboy
anymore:
import { initializeApp } from 'firebase/app'
import { getDownloadURL, getStorage, ref, uploadString } from 'firebase/storage'
exports.handler = async event => {
const payload = JSON.parse(event.body)
return uploadString(ref(getStorage(initializeApp({
/* firebase stuff */
})), payload.name), payload.file.split(',')[1], 'base64').then(file => {
return getDownloadURL(file.ref).then(url => {
return {
body: JSON.stringify({
url: url
}),
statusCode: 200
}
})
})
}
Basically, the file’s base64
content exists as: payload.file.split(',')[1]
. The file gets encoded as follows:
data:application/pdf;base64,actual-base64-content
And thus, we need to split it to get the actual base64
content. That’s required at least to upload the file to Firebase, it might not be required for other providers - but if you wish to convert the base64
to some other format like Buffer
or something else, you’d again have to use split(',')[1]
.
Using the JSON way, you get both, the form fields and the file - MD5 perfect.
Test it here:
https://stoic-brown-d4563d.netlify.app/
Name is supposed to be the file name that you’d like it to be saved as.
You’d get the download URL of the file in console or if the console trims it out, you could always check it in Network tab.