Search code examples
node.jsexpoexpo-goexpo-camera

Expo Go won't upload base64 encoded picture


I'm building an app with Expo Go where I use the expo-camera library. It works fine when testing it on the Emulator in Android Studio, but when using the Expo Go app on an iPhone, I don't receive the picture on the backend.

The code for taking the picture:

  takePicture = async () => {
    if (cameraRef.current) {
      console.log("Taking picture");
      const options = { quality: 0.7, base64: true };
      const data = await cameraRef.current.takePictureAsync(options);
      const source = data.base64;
      if (source) {
        // Save the photo to the backend including information from params
        try{
          let base64Img = `data:image/jpg;base64,${source}`;
          await logPicture(local, base64Img);
        }catch(error){
          console.error("Error saving photo to backend", error);
        }
      }
    }
  };

The logPicture function in React native

export async function logPicture(local, image) {
  const auth = getAuth();
  //Get the token
  console.log("Image", image);
  const token = await auth.currentUser.getIdToken();
  return fetch(apiServerUrl + '/logbook/picture', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`,
      'maxBodyLength': 20000000,
      'maxContentLength': 20000000,
      'maxHttpBufferSize': 1e8 
    },
    body: JSON.stringify(local, image)
  })
  .then((response) => {
    console.log("Response from backend", response);
    return response.json();
  });
}

I can see the base64 string is being generated, in both the emulator and Expo Go client but on the backend (nodejs) the body only contains data from the Local parameter, when taking a picture with the Expo Go client.

Backend code:

router.post("/picture", upload.single('photo'), checkIfAuthenticated, (req, res) => {
  try{
    console.log(req.body);
    //Get the photo as base54String and save it to the filesystem
    var base64String = req.body.photo;
    //Remove the header from the base64 string
    var base64Image = base64String.split(';base64,').pop();
    //Write the file to the uploads folder
    var filename = path.join(__dirname, "../../uploads/" + req.authId + "_" + Date.now() + ".png");
    require("fs").writeFile(filename, base64Image, {encoding: 'base64'}, function(err) {
      if(err){
        console.log(err);
      }else{
        console.log('File created');
      }
    });
    res.status(200);
    res.send("ok");
  }catch(e){

  }
});

Any idea why it works in the emulator but not with Expo Go?


Solution

  • Found the error. The emulator posted a default picture of 19,7 KB which was under the default limit of Express. That led to the picture being processed correctly. When taking the picture with Expo Go, the size is around 1,2 MB which is above the default size limit of Express.

    Adding these to lines to the Express middleware, did the trick:

    app.use(express.json({ limit: '50mb' }));
    app.use(express.urlencoded({ extended: true }));