Firebase ? Supabase ?

Mais pour commencer, de quoi parle t-on au juste ?

Traditionnellement, vous avez une idée d’application, vous savez que vous aller avoir 1 à N clients (web, mobile, …) à développer et donc un serveur pour traiter les demandes de ces différents clients, qu’importe le langage, souvent au travers d’une API REST classique.

Qui dit serveur, dit tout un tas de problématiques à résoudre : l’authentification et l’autorisation des clients, une base de données, des photos de profils à stocker, l’hébergement de tout ça et la mise à l’échelle si vous prévoyez de faire le buzz et qu’il vous faudra encaisser un tas de requêtes que vous n’aviez pas initialement prévues.

Et c’est à ce moment qu’interviennent ces services : un package tout en un qui vous met à disposition des APIs (et généralement les clients qui vont avec) pour gérer tout ça, une interface d’admin, et l’assurance que vous pourrez monter en charge sans soucis.

Grâce à ce genre de services, vous pouvez vous concentrer à 100% sur votre produit et gagner un temps monstrueux !

Supabase API Dashboard

Les différences majeures avec Firebase

Firebase est le service de Google qui vous met à disposition ce package de services et qui existe depuis quelques années déjà, donc forcément beaucoup plus d’APIs pour couvrir vos différents besoins.

Supabase de son côté est encore en beta et couvre pour le moment : l’authentification et l’autorisation, le stockage de fichiers, le stockage de données, les notifications temps réel sur vos données via Websocket et bientôt les fonctions (au sens serverless du terme).

Autre différence notable, Firestore, la base de données fournie par Firebase est une base NoSQL. De son côté, Supabase à opter pour la très réputée base de donnée relationnelle postgres.

Supabase Architecture

Dernier point et non des moindres, la plateforme Supabase repose sur des briques open-source et peut donc être auto-hébergée si vous le souhaitez à la différence de Firebase qui reste une grosse boite noire. Effet de bord de cette ouverture, la communauté peut influencer et contribuer au développement de la plateforme. Vous comprenez maintenant pourquoi ce Supabase me plaît ? 😁

Comment l’utiliser ?

Quand vous utilisez ce genre de services, vous avez le choix :

  • “Sans serveurs” : Vous passez directement par les APIs fournies et n’avez rien à héberger de votre côté, tout votre code se trouvera dans vos applications clientes,
  • Mixte : Vous pouvez mixer les appels directs vers les APIs des services avec des appels vers votre propre back quand le besoin s’en fait sentir (régles métier complexes, orchestration, etc…).

Un cas concret

Prenons un exemple, vous avez une application web React, Vue.js ou autre et vous avez besoin d’authentifier vos utilisateurs à partir d’un fournisseur d’identités type Google. Si vous utilisez Supabase, il vous suffit de vous rendre sur votre dashboard, dans l’onglet Authentication et de renseigner les traditionnels client id et client secret issus de la console du fournisseur d’identités.

Supabase authentication settings

Une fois cette étape de configuration faite, direction votre code client javascript, un petit npm install @supabase/supabase-js, vous placez votre bouton sur votre page et il ne vous reste plus qu’à implémenter la fonction qui authentifie l’utilisateur :

import { createClient } from "@supabase/supabase-js";

// On instancie le client supabase qui nous facilite l'accès à la plateforme
const supabaseClient = createClient(
  "<l'url de votre projet supabase>",
  "<clé d'api publique supabase>"
); // Tous deux récupérés depuis le dashboard

// En handler du bouton de connexion
function handleLoginClick() {
  // Et boum ! Vous êtes redirigé vers Google pour autoriser l'application, supabase se charge du reste
  supabaseClient.auth.signIn({ provider: "google" });
}

// ... Plus loin dans votre application
function getConnectedUser() {
  return supabaseClient.auth.user();
}

Besoin d’authentifier l’utilisateur sur votre propre API ?

// Côté client, vous pouvez sortir le jeton d'accès avec
const token = supabaseClient.auth.session()?.access_token;

// ... Et sur votre serveur
async function (request, response) {
  const { data, error } = await supabaseClient.auth.api.getUser(request.headers.token);

  if (error) {
    return res.status(403).end();
  }

  return res.status(200).json({ currentUser: data });
}

Sur le dépôt Github officiel, vous pouvez retrouver tout un tas d’exemples bien utiles !

L’accès à la base postgres

L’authentification, c’est ok, maintenant comment on accède à la base postgres ? Déjà, vous commencez par créer votre schéma via l’éditeur de requêtes intégrés à Supabase (ou un client avec la chaîne de connexion que vous pouvez récupérer aisément) :

Supabase query editor

Ensuite vous avez de nouveau le choix, vous pouvez passer par l’API fournie automatiquement pour tous les objets du schéma public et réutiliser le client comme ceci, côté back ou front :

async function getRessources() {
  const { data, error } = await supabaseClient
    .from("votreTable")
    .select("id,uneColonne,etUneAutre");

  // et tout un tas d'autres méthodes pour filtrer, trier, paginer, insérer, modifier, etc...

  if (error) {
    return [];
  }

  return data;
}

Ou alors vous récupérez les informations de connexion sur votre interface et vous avez accès à la base de données, vous pouvez appliquer des migrations, utiliser votre ORM préféré sans vous soucier de l’infrastructure, bref, du grand classique.

Et l’autorisation dans tout ça ?

Maintenant si vous décidez de vous passer d’un serveur, la question que vous devez vous poser est comment fonctionne l’autorisation, on ne souhaite pas que n’importe qui puisse modifier la base de données au travers de l’API publique de Supabase !

Et bien dans ce cas, tout à été prévu et vous pouvez directement utiliser les Row Level Security de postgres et vous assurez que l’utilisateur possède les droits suffisants, par exemple :

alter table public.votreTable enable row level security;
create policy "Tout le monde a accès aux données"
  on public.votreTable for select using (
    true
  );
create policy "Mais seul les utilisateurs authentifiés peuvent insérer des données"
  on public.votreTable for insert with check ( auth.role() = 'authenticated' );

Par défaut, les Row Level Security sont désactivées à la création des tables ce qui signifie que n’importe qui peut accéder à votre table via l’API si cette dernière est définie dans le schéma public.

Si vous vous demandez comment ça fonctionne, c’est en fait très simple. Quand vous effectuez un appel sur l’API auto-générée par Supabase, le jeton de l’utilisateur connecté est envoyé à la base postgres, et grâce à des extensions activées, les informations du jeton se retrouvent disponibles via auth.role(), auth.uid() et quelques autres fonctions.

On fait le point

Voilà pour ce petit tour très rapide du propriétaire. Après avoir joué un peu avec, j’avoue avoir mieux compris l’intérêt du serverless et de ce genre de services. Toute l’infrastructure est déportée, l’intégration est simple, l’interface bien pensée, le pricing plutôt intéressant avec une offre gratuite généreuse.

Si je suis arrivé à tester Supabase, c’est suite à cette série de vidéos qui m’a permis de mieux appréhender la fameuse JAMStack et même si on reste lié à un fournisseur, ce qui m’a vraiment plus, c’est la simplicité de mise en oeuvre et de déploiement (surtout couplé à Vercel).

Vous l’aurez compris, le fait que Supabase soit open-source me plaît beaucoup, on se sent moins piégé, on peut à tout moment faire un dump de la base postgres via le client psql ou décider de rappatrier toute la stack sur nos propres serveurs.

Cet article n’est pas exhaustif et Supabase évolue très vite en ce moment, je vous invite donc à garder un œil dessus si vous avez ce genre de besoins 😉