From user profile images to invoice PDFs to cute dog pics, it’s hard to find a modern application that doesn’t need to store files. We’re excited to announce that as of today, every Gadget application can store and serve files in the cloud, with zero configuration. Gadget accepts uploads in a variety of formats, stores file contents securely in Google Cloud Storage, and serves files using a performant CDN.
Here’s how it works:
There’s no time spent setting up cloud buckets, configuring security rules, or dealing with cross origin headers -- just add a File field and you’re set to go.
The File field type supports validations just like any other field, so you can limit the size or nature of files your app will store. File fields can be edited or changed within effect code snippets along with the rest of the record as well. And finally, you can limit file access using the same role-based permission-ing system that handles access to other fields and records.
We’ve also tried to make it as easy as possible to write frontend code to create files in Gadget. You can submit files to your Gadget app’s API using base64 encoded strings, using multipart form requests from the browser, or using an existing URL to a file. And finally, Gadget supports direct upload to cloud storage, which gives a great user experience when uploading bigger files. Your generated Gadget API client already knows how to communicate with the Gadget API for all these methods, so uploading files works just the same as any other action.
Uploading and serving files has been something many folks have had to sort out many times over in the past. But, it can be really annoying to flesh out this feature with the extra security and performance that many customers have begun to expect. With the File field, we've tried to give both users and developers a best-in-class experience right out of the box.
For the user experience, we focused on making building excellent web forms easy, and a big part of that is giving users feedback as they fill in form's fields. Users are able to correct mistakes quickly right after making them, instead of filling out the entire form, hitting save, and having to scroll around and fix various things they’ve already forgotten touching. File uploads pose a similarly dangerous user experience challenge where they can slow down the cycle of a user entering data, submitting it, waiting for the files to upload and the data to be validated, and then learning that they got something wrong and having to do it again.
Instead, we should try to get users through their forms as fast as possible, and one great way to do that is to start uploading any files as soon as they select them, instead of waiting for them to hit save to begin. That way, while they are filling out any other fields, the upload can progress in the background and hopefully complete before they’re finished. The uploaded file can also be re-used between different form submissions, so that if other fields happen to be invalid on the form, the file doesn’t need to be uploaded a second time.
The process works like this:
This approach is called “direct uploads” and gives the best user experience. It requires a bit fancier server that knows how to create these direct upload URL targets and tokens as well as a bit fancier client that knows how to work with these files. Gadget makes this easier by already having the server, cloud storage bucket, and secure URL signing set up for you. We use Google Cloud Storage’s signed upload URL functionality to let user browsers upload files right into cloud storage which performs way better than us proxying it. We also use a different bucket for direct uploads so we can secure it differently, and so we can garbage collect unconsumed directly uploaded files easily.
We’ve got two examples of direct upload frontends to help you get started. There’s a raw React example here, and one using an amazing open source file picker widget called Uppy here. And as always, if you have any questions or could use some help, come talk to us on Discord!