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.
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 plusCré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 plusUpload 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