Aller au contenu principal

Stockage de fichiers (au revoir buckets S3)

Bien que le bucket S3 soit devenu une référence voire même le choix par défaut quand on commence un projet, on aimerait vous mettre en garde en redétaillant l'intégration d'un bucket S3 au sein d'un applicatif.

Si vous utilisez du S3 vous allez normalement stocker vos fichiers dans un espace distinct de votre base de données. Chaque fichier aura une URL unique, et dans votre base de données vous garderez en référence cette URL. Vous vous retrouvez dans la situation où les deux peuvent ne plus être synchronisés, avoir l'URL dans votre base de données ne veut pas dire que le fichier existe sur votre bucket S3.

Sachez qu'une PostgreSQL est capable de gérer au sein d'une colonne des fichiers faisant maximum 1 Go chacun, il faut pour cela utiliser le type BYTEA (qui utilise le TOAST).

Information

Il existe aussi la possibilité de stocker des "large objects" qui peuvent faire jusqu'à 4 To chacun, il faut une étape supplémentaire pour les ajouter avant de les référencer dans une table traditionnelle. Et cela pose des questions de volumétrie qui seront abordés plus loin.

Vous devez spécifier et quantifier ce que vous allez héberger pour dire oui ou non aux buckets S3.

Un élément important qui est mentionné dans le chapitre légal et qui doit être pris en compte dans votre calcul : la CNIL recommande de ne pas conserver les données utilisateurs plus de 2 ans.

Cas concrets :

  1. Si je sais que mon produit ne va héberger que des photos de profil des agents publics et les logos de toutes les collectivités de France. Je sais d'avance que la totalité des fichiers ne dépassera jamais une certaine limite. Ma PostgreSQL suffit ;
  2. Si mon outil reçoit des demandes de médiations et que chaque citoyen et agent public peut ajouter à chaque demande des pièces justificatives (limitées à 5 Mo chacune), a priori il n'y a pas de limite (cela peut être exponentiel). Sauf que l'on sait historiquement qu'il y a en moyenne 5 fichiers par dossier, et 10 000 dossiers créés par an. Comme l'outil supprime les dossiers après 2 ans pour respecter la recommandation CNIL, le stockage reste acceptable et une PostgreSQL devrait suffire ;
  3. Si mon outil archive les médias réalisés durant des événements publiques, j'accepte ainsi des photos en haute qualité (10 Mo ou plus) et des vidéos qui peuvent faire plusieurs heures (plusieurs Go). De plus, du fait de la volonté d'archiver la recommandation CNIL n'est pas appliquée. Je me retrouve avec un enjeu stratégique sur le stockage, ma PostgreSQL n'est pas adaptée, je choisis du S3.

Points importants (hors problématiques de stockage) :

  • Nous devons rester sur des tailles de fichiers acceptables quand on passe via PostgreSQL car c'est notre propre API qui sera sollicitée pour servir le flux ;
  • En utilisant une base PostgreSQL pour le stockage il ne faut jamais essayer de produire vous-même la logique d'upload d'un fichier. Cela implique beaucoup de technique : headers HTTP, le "resumable upload" (fait de reprendre une upload si la connexion internet est perdue durant quelques secondes)… Nous préconisons plutôt d'utiliser tus (client et serveur) sachant qu'ils proposent une intégration dans l'API Next.js ;
  • Si vous utilisez des buckets S3, ne faites pas transiter les fichiers par votre API. Vous avez sûrement choisi S3 car il est question de volumétrie importante. Le fait d'utiliser votre API en intermédiaire met un point de congestion et fait reposer sur vous le fait de bien dimensionner votre API alors qu'une upload/lecture peut être anecdotique (sachant que ça peut en plus perturber vos opérations sensibles sur l'API). Nous recommandons dans ce cas de choisir un fournisseur S3 qui permet de "signer des URLs" que ce soit en lecture ou en upload. Avec cette architecture aucun fichier ne transite via votre API :
    1. Votre frontend demande à l'API "je veux uploader un fichier" ;
    2. L'API renvoie une nouvelle URL signée du provider S3 ;
    3. Le frontend peut uploader son fichier directement sur l'URL signée (en utilisant une librairie cliente compatible comme tus) et obtient l'URL finale du fichier uploadé ;
    4. Le frontend peut transmettre l'URL du fichier uploadé à l'API ;
    5. L'API est en mesure de valider le fichier de façon synchrone (ou non), et d'enregister l'URL en base de données.

Notez que les technologies comme tus ou S3 ne gèrent pas les règles de sécurité propres à votre métier (qui peut uploader ? qui peut lire ce fichier ?). C'est à vous de gérer cette partie. Nous abordons cela plus en détail dans le chapitre sur la sécurité.

info

Écrire et lire des fichiers dans votre base de données va forcément utiliser un peu plus de ressources (notamment la bande passante). N'hésitez pas à "augmenter" les performances de votre base si besoin, et à dimensionner le tuyau d'entrée pour faire passer les fichiers :

Il faudrait augmenter la configuration dans le fichier du endpoint d'upload en exportant par exemple :
my-endpoint.tsx
export const config = {
api: {
bodyParser: {
sizeLimit: '10mb',
},
},
};