Supabase - Bucket

Présentation

Depuis quelques temps (voir très longtemps), Supabase propose en plus de tout le reste, un espace de stockage pour des fichiers. Le précédent sujet étant la prise de photos, c’était une occasion de tester.

Fait dans la foulée de la journée précédente donc court :)

Création

Créer le bucket peut se faire via des commandes, mais le plus simple est de passer par l’interface. Là, une première question : public ou non public. Dans le cas du test, j’ai laissé “Public” mais cela reste intéressant de pouvoir fermer les portes si besoin.

L’écran est simple donc la création aussi :

RLS

Comme pour les tables, il est possible de définir assez finement sur les droits que l’on donne aux utilisateurs :

Il est donc possible de mettre des règles pour filtrer l’accès et les actions possibles. A noter que si au départ, l’accès public est donné, il n’y aura pas de restriction. Dans le cadre de mon test, j’ai indiqué qu’à minima, il fallait être authentifié.

Enregistrement d’un fichier

Comme souvent avec Supabase, c’est simple :

 const { data: dataUpload, error: errorUpload } = await supa.storage.from('photos')
    .upload(
        filename,
        file,
        {
            upsert: true, // Pour forcer le remplacement
        }
    );

Les paramètres :

  • filename : le nom du fichier (oui :)),
  • file : le fichier (non ?),
  • options :
    • upsert : permet de forcer le remplacement.

Ma “seule” difficulté a été de transformer le flux envoyé par CameraPreview en un fichier. Au début, l’enregistrement enregistrait juste un texte ce qui n’est pas pratique. Après quelques recherches, la fonction car cela peut servir :

    private static dataURLtoFile(dataurl: string, filename: string): File | undefined {
        const arr = dataurl.split(",");
        if (arr && arr.length > 0) {
            const mime = arr[0].match(/:(.*?);/)![1];
            const bstr = atob(arr[arr.length - 1]);
            let n = bstr.length;
            const u8arr = new Uint8Array(n);
            while (n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            return new File([u8arr], filename, { type: mime });

        }
        return undefined;
    }

Récupérer les fichiers

Sur la base de la doc, il ne semble pas avoir de moyens de récupérer une liste de fichiers. Il est possible de récupérer un fichier par contre pas forcément moyen de lister le contenu via les APIs (du moins, je n’ai pas trouvé). Donc il faut créer une table spécifique pour enregistrer les fichiers :

photo.publicURL = supa.storage.from("photos").getPublicUrl(dataUpload.path).data.publicUrl;

// Enregistrement en base de données
const { data: dataInsert, error: errorInsert } = await supa.from("photo").insert
    ({
        publicURL: photo.publicURL,
        label: photo.label,
        uniqueId: photo.uniqueId,
        path: photo.path
    });

Et là, un point de risque : comment gérer l’atomicité entre l’upload et l’enregistrement.

Note : le système permet de calculer directement l’URL public : supa.storage.from("photos").getPublicUrl(dataUpload.path).data.publicUrl

Suppression du fichier

Idem très simple :

const { data: dataFile, error: errorFile } = await supabase.storage
    .from('photos')
    .remove([photo.path!]);

Un point embêtant, la suppression semble ne fonctionner uniquement que sur le path. C’est dommage car supabase retourné un ID. Cela impose un suivi en cas de déplacement du fichier dans un autre système.

Conclusion

Temps passé : 30 min donc autant dire rien. Mais en 30 min, l’application était en capacité de téléverser des fichiers, de les servir et les supprimer …

A suivre mais ce sera pour une prochaine fois.