javascriptreactjsnode.jsmultipartform-dataform-data

Payload empty when send as new FormData()


I'm trying to pass images to my node server but whatever i'm trying the payload is constantly empty when I pass it as a const formData = new FormData();, as regular I do get the correct informations (except for the images that cannot be translated without the new FormData()) but the rest is sent through the payload.

This is my API:

/// POST SEND MESSAGE  ///

export const postSendMessage = async (id, data) => {
  const headers = {
    'Content-Type': 'multipart/form-data',
    'Accept-Language': currentLang,
  }
  const body = {
    senderId: data.senderId,
    text: data.text,
    images: data.images,
  }
  try {
    const response = await axios.post(`http://localhost:3001/patient/${id}/message`, body, { headers })
    return response
  }
  catch (error) {
    console.error('error', error);
  }
  return null
};

And this is the Frontend:

const ChatMessageInput = ({ conversationId }) => {

  const userContext = useContext(AuthContext);
  const fileRef = useRef(null);

  const [message, setMessage] = useState('');
  const [images, setImages] = useState([]);

  const handleAttach = (event) => {
    const newImage = event.target.files[0];
    if (newImage && newImage.type.includes('image')) {
      setImages(prevImages => [...prevImages, newImage]);
    }
  };

  const handleChangeMessage = useCallback((event) => {
    setMessage(event.target.value);
  }, []);

  const handleSendMessage = async (event) => {
    if (event.key === 'Enter') {
      try {
        const formData = new FormData();
        formData.append('text', message);
        formData.append('images', images);
        formData.append('senderId', userContext.user.id);
        const messageSent = await API.postSendMessage(conversationId, formData);

        setMessage('');
        setImages([]);
      } catch (error) {
        console.error(error);
      }
    }
  };

  return (
    <>
      <InputBase
        value={message}
        onKeyUp={handleSendMessage}
        onChange={handleChangeMessage}
        placeholder="Type a message"
        endAdornment={
          <Stack direction="row">
            <IconButton onClick={() => fileRef.current.click()}>
              <Iconify icon="solar:gallery-add-bold" />
            </IconButton>

          </Stack>
        }
      />
      <input type="file" ref={fileRef} style={{ display: 'none' }} onChange={handleAttach} />
    </>
  );
}

From what I understand you cannot console.log formData, but when I console.log messages or images I do get the correct value. I'm missing something here.

Thank you


Solution

  • First, When you need to append multiple images to the formData, you shouldn't pass the images array, but append them individually, for example "image" + index as a key and the image as a value.

    Second, in the postSendMessage method, the second parameter is formData, you need to pass it as it is to the axios post request.

    export const postSendMessage = async (id, formData) => {
      const headers = {
        'Accept-Language': currentLang, // Do not set Content-Type here
      }
      try {
        const response = await axios.post(`http://localhost:3001/patient/${id}/message`, formData, {
          headers: headers,
        });
        return response;
      }
      catch (error) {
        console.error('error', error);
      }
      return null;
    };
    
    const handleSendMessage = async (event) => {
      if (event.key === 'Enter') {
        try {
          const formData = new FormData();
          formData.append('text', message);
          formData.append('senderId', userContext.user.id);
          images.forEach((image, index) => {
            formData.append(`images[${index}]`, image);
          });
          const messageSent = await API.postSendMessage(conversationId, formData);
    
          setMessage('');
          setImages([]);
        } catch (error) {
          console.error(error);
        }
      }
    };