I'm having trouble sending a photo, in a PUT route, be it with Axios or Fetch, anyway, my Nodejs backend is configured and the whole upload process works normal testing by Insonmia, but in React Native It does not work properly.
BACKEND - CONTROLLER FOR UPDATING USER DATA
async updateUserData(req: Request, res: Response, next: NextFunction) { const { id } = req.params; const { username, status } = req.body as IBodyData; try { const userExists = await knex('tb_user') .where('id', Number(id)) .first(); if (!userExists) { return res.status(400).json({ error: 'User does not exist.' }); } const serializedUserInfo = { photo: `${process.env.BASE_URL}/uploads/${req.file.filename}`, username, status, }; const updateInfo = await knex('tb_user') .update(serializedUserInfo) .where('id', Number(id)); if (!updateInfo) { return res.status(400).json({ error: 'Error updating data.' }); } return res.json(updateInfo); } catch(err) { return res.status(500).json({ error: 'Error on updating user.' }); } }
BACKEND - ROUTE
routes.put('/updateuser/:id', multer(multerConfig).single('userphoto'), UserController.updateUserData);
CONFIG MULTER
export default { fileFilter: (req: Request, file, cb) => { const allowedMimes = ['image/jpeg','image/jpg','image/pjpeg','image/png', ]; if (!allowedMimes.includes(file.mimetype)) { return cb(new Error('Invalid file type.')); } return cb(null, true); }, limits: { fileSize: 2 * 1024 * 1024, }, storage: multer.diskStorage({ destination: resolve(__dirname, '..', '..', 'uploads'), filename: (req: Request, file, cb) => { const filename = `${randomBytes(6).toString('hex')}-${file.originalname}`; return cb(null, filename); } })} as Options;
REACT NATIVE - FUNCTION FOR GET DATA OF PHOTO AND SET ON STATE
function handleUploadImage(image: IImagePickerResponse) { if (image.error) { return; } if (image.didCancel) { return; } if (!image.uri) { return; } setSelectedImage({ fileName: image.fileName, fileSize: image.fileSize, type: image.type, uri: image.uri, }); }
REACT NATIVE - FUNCTION FOR SEND DATA IN API
async function handleSaveChange() { try { const formData = new FormData(); formData.append('userphoto', { uri: Platform.OS === 'android' ? selectedImage?.uri : selectedImage?.uri?.replace('file://', ''), type: selectedImage.type, name: selectedImage.fileName, }); formData.append('username', usernameInput); formData.append('status', statusInput); console.log(formData); await api.put(`/updateuser/${userData?.id}`, formData, { headers: {'Content-Type': 'multipart/form-data', }, }); // const updateUser = await fetch('http://192.168.2.8:3333/updateuser/1', { // method: 'POST', // headers: { // 'Content-Type': 'multipart/form-data', // }, // body: formData, // }) // .then((response) => { // response.json(); // }) // .then((response) => { // console.log(response); // }) // .catch((err) => console.log(err)); return Toast.success('Informações alteradas com sucesso.'); } catch (err) { const {error} = err.response.data; return Toast.error(error); } }
obs: A note to take into account is that in the formData.append ('userphoto', value)
part if the value has sent a normal json object, the request is neither made nor the Network Error
error even IP address being correct the port too, anyway, and if I use formData.append ('userphoto', JSON.stringfy(value))
the request is made normally but in the backend the photo arrives as undefined
and the rest of fields are sent and received normal.
I really tried several things and I couldn't, I changed the type of the PUT method to POST without success, add 'Accept': 'application/json'
without success, as I said, the normal sending by Insomnia is working.
Finally, here is the lib configuration I used to get the photo:
REACT NATIVE IMAGE PICKER
ImagePicker.showImagePicker( { title: 'Selecione uma imagem', takePhotoButtonTitle: 'Tirar foto', chooseFromLibraryButtonTitle: 'Escolher da galeria', cancelButtonTitle: 'Cancelar', noData: true, // storageOptions: { // skipBackup: true, // path: 'images', // cameraRoll: true, // waitUntilSaved: true, // }, }, handleUploadImage,)
SOLVED
Apparently it was a problem with the version of React Native, I am currently using version 0.62.XX
To resolve, just comment line number 43 in the file:
android/app/src/debug/java/com/mobile/ReactNativeFlipper.java
The code is this:
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor (networkFlipperPlugin));