Upload de fichier avec API Platform, Symfony et ReactJS

Par Jean-Maxime BOULOC le 20/01/2022
Upload de fichier avec API Platform, Symfony et ReactJS

Je vais vous montrer comment uploader un fichier depuis une application en ReactJS vers une API Symfony réalisé avec API Platform

Versions utilisées :

  • Symfony 5.3
  • API Platform 2.6.5
  • ReactJS : 17.0.0

La partie Back avec Symfony et API Platform

Pour commencer, je vous invite à suivre le tutoriel du site API Platform pour réaliser la partie API de votre application. C’est ce que j’ai utilisé pour mettre en place mon API me permettant d’uploader des fichiers simplement. Dans le tutoriel, j’ai choisi d’avoir une Entity MediaObject à part, qui n’est donc pas intégré à une autre Entity de mon application. Je vais donc avoir une route /api/media_objects pour uploader mon fichier.

Passons au front avec ReactJS

Passons à la partie front en ReactJS. Je vais prendre un simple formulaire qui uploade un fichier comme ceci :

import React from 'react';
import { FormControlLabel } from '@material-ui/core';
import { Controller, useForm } from 'react-hook-form';

export default function Upload() {
  const {
    control, handleSubmit, setValue, getValues
  } = useForm();

  const onSubmit = (data) => {
    console.log('Formulaire envoyé');
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="file"
        accept="image/*"
        control={control}
        render={({ field, fieldState }) => (
          <FormControlLabel
            label="File"
            control={(
              <input
                type="file"
                accept="image/*"
                {...field.name}
                {...fieldState}
                name="file"
                onChange={(e) => setValue('file', e.target.files[0])}
              />
            )}
            labelPlacement="start"
          />
        )}
      />
      <input type="submit" value="Envoyer" />
    </form>
  );
}

Un peu d’explication. Pour avoir le contrôle de mon input de type file j’utilise le composant Controller qui me permet d’avoir la fonction onChange de mon input et de sauvegarder le fichier dans un state. J’utilise également quelques fonctions de useForm pour faciliter la gestion du formulaire.

Pour le moment, mon composant Upload n’est qu’un simple input de type file avec un bouton pour envoyer le formulaire. Un message dans la console s’affiche lorsque je soumets le formulaire. Je vais pouvoir effectuer l’envoi de ce fichier vers mon API. Pour cela, je vais utiliser fetch pour effectuer mes requêtes HTTP facilement. Il existe aussi axios si vous voulez y jeter un oeil.

Envoi du fichier via la fonction fetch

Voici le code qui va me permettre d’envoyer mon ficher à mon API :

const sendFile = async (file) => {
  const form = new FormData();
  form.append('file', file);
  const response = await apiCall('/api/media_objects', 'POST', form);
  return response.json.id;
};

const apiCall = async (endpoint, method = 'GET', data = null, headers = null) => {
  const res = await fetch(endpoint, {
    method,
    headers: {
      ...headers,
    },
    body: data,
    //mode: 'no-cors',
  });
  const text = await res.text();
  let json = {};
  if (text !== '') {
    json = JSON.parse(text);
  }

  return {
    status: res.status,
    json,
  };
};

La fonction sendFile permet de formater la donnée pour pouvoir l’envoyer à dans le bon format.

Ma fonction apiCall permet d’envoyer le fichier à mon API et de gérer la réponse de retour.

Problèmes CORS

ATTENTION : En travaillant en local, il y a souvent des erreurs CORS. Dans mon cas, je travaille avec nelmio/cors-bundle côté Symfony. Côté ReactJS et plus précisément sur la fonction fetch , il y a la possibilité d’ajouter le mode no-cors . Mais l’ajout de ce mode dans mon cas m’empêchait de faire ma requête HTTP sans erreur. C’est pour cela que je l’ai mis en commentaire dans mon exemple.

Code ReactJS complet

import React from 'react';
import { FormControlLabel } from '@material-ui/core';
import { Controller, useForm } from 'react-hook-form';

export default function Upload() {
  const {
    control, handleSubmit, setValue, getValues,
  } = useForm();

  const apiCall = async (endpoint, method = 'GET', data = null, headers = null) => {
    const res = await fetch(endpoint, {
      method,
      headers: {
        ...headers,
      },
      body: data,
      //mode: 'no-cors',
    });
    const text = await res.text();
    let json = {};
    if (text !== '') {
      json = JSON.parse(text);
    }

    return {
      status: res.status,
      json,
    };
  };

  const sendFile = async (file) => {
    const form = new FormData();
    form.append('file', file);
    const response = await apiCall('/api/media_objects', 'POST', form);
    return response.json.id;
  };

  const onSubmit = async () => {
    const response = await sendFile(getValues('file'));
    console.log(response);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="file"
        accept="image/*"
        control={control}
        render={({ field, fieldState }) => (
          <FormControlLabel
            label="File"
            control={(
              <input
                type="file"
                accept="image/*"
                {...field.name}
                {...fieldState}
                name="file"
                onChange={(e) => setValue('file', e.target.files[0])}
              />
            )}
            labelPlacement="start"
          />
        )}
      />
      <input type="submit" value="Envoyer" />
    </form>
  );
}

Et voilà comment envoyer un fichier depuis une application ReactJS vers son API Symfony géré avec API Platform.

Derniers articles

Retrouvez mes derniers articles sur le développement web, le PHP, Symfony, les SaaS et bien d'autres sujets.

art cover

Starter Kit Symfony 7 pour Développeurs Web

Découvrez le Starter Kit Symfony 7 : Gagnez du temps sur vos projets web avec des fonctionnalités préconfigurées !"

Lire plus
art cover

Créer un SaaS en tant que développeur web

En tant que développeur web, la création de site est quelque chose que nous faisons au quotidien. Et pourquoi pas gagner sa vie via un SaaS ?

Lire plus
art cover

Upload de fichier avec API Platform, Symfony et ReactJS

Je vais vous montrer dans cet article comment uploader un fichier depuis une application ReactJS vers une API Symfony avec API Platform.

Lire plus