carlosbm
carlosbm14mo ago

Upload Video from a RN Expo app to the Convex Storage

Hello! I'm having trouble saving a video from a RN Expo app to the Convex Storage. In the examples, there are only references to upload images. I'm trying to build a formData and doing several things, but I cannot get it working. I managed to upload the video to the Storage, and I see it uploaded with the proper size, but cannot change the name, nor I can play the video after downloading it because it is saved in a different extension. This is the code I have right now, if someone could help me would be great! Thanks!
const postUrl = await generateUploadUrl();

const form = new FormData();
form.append("video", {
uri,
type: "video/*",
name: "video.mp4",
});

// Step 2: POST the file to the URL
const result = await fetch(postUrl, {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
body: form,
});

const { storageId } = await result.json();
// Step 3: Save the newly allocated storage id to the database
await saveVideoStorageId({ videoStorageId: storageId });
const postUrl = await generateUploadUrl();

const form = new FormData();
form.append("video", {
uri,
type: "video/*",
name: "video.mp4",
});

// Step 2: POST the file to the URL
const result = await fetch(postUrl, {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
body: form,
});

const { storageId } = await result.json();
// Step 3: Save the newly allocated storage id to the database
await saveVideoStorageId({ videoStorageId: storageId });
4 Replies
lee
lee14mo ago
Convex does not store filenames for file storage, and I don't think it supports multi-part form data for file uploads. instead, we recommend you store the file's contents in storage and filename in the db, like this:
const result = await fetch(postUrl, { method: "POST", headers: { "Content-Type": "video/mp4" }, body: [video blob]);
const { storageId } = await result.json();
await saveVideoStorageId({ videoStorageId: storageId, filename: "video.mp4" });
const result = await fetch(postUrl, { method: "POST", headers: { "Content-Type": "video/mp4" }, body: [video blob]);
const { storageId } = await result.json();
await saveVideoStorageId({ videoStorageId: storageId, filename: "video.mp4" });
Then the storage download URL will have Content-Type: video/mp4 so it should display in an html video player. If you want to download the video, one way would be:
const video = useQuery(api.video.get);
if (!video) return null;
const { filename, videoStorageUrl } = video;
return <a href={videoStorageUrl} download={filename}>Download {filename}</a>;
const video = useQuery(api.video.get);
if (!video) return null;
const { filename, videoStorageUrl } = video;
return <a href={videoStorageUrl} download={filename}>Download {filename}</a>;
and a different way would be to make an HTTP action for the download that uses ctx.storage.get(videoStorageId) for the body and returns a header Content-Disposition: attachment; filename="video.mp4"
Web Dev Cody
Web Dev Cody7mo ago
sorry to revive an old thread, but I'm currently trying to store mp4 files on convex and then later allow the user to download them. using the http endpoint has a 20 mb limit, so I don't think that will work for me. This example of using a download attribute on the a doesn't seem to work for me, it still just redirects me to the new page and plays the video directly in the browser I don't think download attribute works for cross-origin I wonder if it would be possible to add an options to ctx.storage.getUrl(storageId, options), and options I could specify a download=true & filename which convex could just add for me on the generated url and on the convex backend y'all just attach those headers, or add an ability for developers to put some type of middleware in front of the response for adding custom headers https://dapper-cuttlefish-318.convex.cloud/api/storage/080167f-13b9-45a5-9ba9-79c5649e0598?download=true&filename=video.mp4 at this point, my only work around I can think of would be to setup a separate api, make a download endpoint, download the file from convex storage, and send that to my user
lee
lee7mo ago
great question. it would be nice if http endpoints had no size limit, which would allow you to do the middleware in an http action. adding the filename to the url also sounds reasonable. i'll ask around if anyone has a solution.
ballingt
ballingt7mo ago
yeah if you could add a Content-Disposition: attachment; filename="filename.jpg" header that would do it, but indeed either we need to add it for you (controlled by query params as you suggest sounds reasonable) or we need to allow you to use http endpoints for this

Did you find this page helpful?