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 ci-dessous autour des thérapeutes bien-être et des coachs.

art cover

Pourquoi faire appel à un professionnel pour créer son site internet en tant que thérapeute ou coach

Découvrez pourquoi un site professionnel est essentiel pour thérapeutes et coachs, avec des conseils sur la visibilité et un accompagnement personnalisé.

Lire plus
art cover

Pourquoi un site web est essentiel pour un thérapeute ?

Découvrez 8 raisons clés pour lesquelles un site web est indispensable aux thérapeutes : visibilité, crédibilité et génération de nouveaux clients

Lire plus
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