DEV Community

Aaron K Saunders
Aaron K Saunders

Posted on • Edited on

How To Upload Files To Supabase Storage Buckets and Write Data To Supabase Using Remix

Update: Source code updated 05/22/2022 to version 1.5.1 of remix-run


Overview

Simple application showing file upload and writing database records using Remix and Supabase

We show how Actions and Loaders work to manager working with server for data and to make API calls. In both of the examples presented in video, the actions are processing the form data and then making the appropriate calls to Supabase. We then take the responses we get from Supabase and populate action data which is returned to the page and rendered appropriately.

Remix is a full stack web framework that lets you focus on the user interface and work back through web fundamentals to deliver a fast, slick, and resilient user experience.

The Video

Writing Data

This is the action function related to writing new record to the database. The form that is being processed has an input elements for all of the fields to be written to database. On successful write to database, we redirect back to the default route of application

export const action = async ({ request }) => {
  // get data from form
  let form = await request.formData();
  let name = form.get("name");
  let description = form.get("description");
  let state = form.get("state");

  // use form information to write to supabase
  const { data, error } = await supabaseClient
    .from("chargers")
    .insert([{ name, description, state }]);

  // if no error, back to home page... index.jsx
  if (!error) {
    return redirect("/", {});
  }

  // else stay on page and return error information
  return { data, error };
};
Enter fullscreen mode Exit fullscreen mode

Uploading Files

Currently a bug in Remix when uploading large files. In this example I am only using small files to show how the process works

This example is derived from the Remix documentation on uploadHandler which can be found here

Access To Storage Buckets

Creating buckets in Supabase is beyond the scope of this video, you can read more here, but I wanted to include the script for creating the appropriate policy because I got stuck on this issue.

This is the SQL script I used to allow you to upload files to Supabase Storage. I am not restricting access for the purpose of this demo but you can read up more or on creating policy here in the Supabase Documentation

replace my bucket id "images" with the name of your bucket

create policy "ALL images are publicly accessible."
  on storage.objects for select
  using ( bucket_id = 'images' );

create policy "Anyone can upload an image."
  on storage.objects for insert
  with check ( bucket_id = 'images' );

create policy "Anyone can update an image."
  on storage.objects for update
  with check ( bucket_id = 'images' );
Enter fullscreen mode Exit fullscreen mode

This is the action function related to file upload. The form that is being processed has an input element with the id my-file

export const action = async ({ request }) => {
  try {
    /**
     *
     * @param {*} param0
     * @returns
     */
    let uploadHandler = async ({ name, stream, filename }) => {
      console.log("in uploadHandler");

      if (name !== "my-file") {
        stream.resume();
        return;
      } else {
        console.log(name, filename);
      }

      // Get the file as a buffer
      const chunks = [];
      for await (const chunk of stream) chunks.push(chunk);
      const buffer = Buffer.concat(chunks);

      // call supabase function for uploading to bucket
      const { data, error } = await supabaseClient.storage
        .from("images")
        .upload(filename, buffer);
      if (error) {
        throw error;
      }

      // return information up uploaded file
      return JSON.stringify({ data });
    };

    // get file info back after image upload
    const form = await unstable_parseMultipartFormData(request, uploadHandler);

    //convert it to an object to padd back as actionData
    const fileInfo = JSON.parse(form.get("my-file"));

    // this is response from upload handler
    console.log("the form", form.get("my-file"));

    // return success action data
    return fileInfo;
  } catch (e) {
    // return error action data
    return { error: e };
  }
};
Enter fullscreen mode Exit fullscreen mode

Top comments (7)

Collapse
 
yhoung24909577 profile image
obiabo Immanuel

i am finding it difficult to upload data to @supabase_io

after the correct function its not still uploading to supabase
Enter fullscreen mode Exit fullscreen mode
Collapse
 
aaronksaunders profile image
Aaron K Saunders

Going to need a bit more information to be off any help

Collapse
 
yhoung24909577 profile image
obiabo Immanuel

after using my Api url and Api key, i tried uploading to my bucket with JS its not going through

Thread Thread
 
nathbabs profile image
Nathaniel

Hi @yhoung24909577 , what problem are you facing.....like what error.

Collapse
 
wong2 profile image
Wang Dàpéng

for await (const chunk of stream) chunks.push(chunk)

This line breaks the benefit of streaming upload, you're reconstructing the file in memory, and then upload it to supabase.

Collapse
 
gafemoyano profile image
Felipe Moyano

Did you deploy the app with amplify as well, or where is it hosted?

Collapse
 
karmablackshaw profile image
KarmaBlackshaw

Was going nuts why uploading file always return "Invalid JWT" until I found your blog. The policy helped me! Thanks!