DEV Community

Cover image for Send Images from React Native to Serverless Functions
Ozan Bolel
Ozan Bolel

Posted on

Send Images from React Native to Serverless Functions

Sending files to your backend in React Native can be tricky especially on Android. If you are going to use your REST API to do that, perhaps making a multipart/form-data request is the most straight forward option. But parsing that request in a serverless environment can be equally torturous. Luckily there are some libraries out there, making it a lot easier. In this post, we are going to use two of those libraries. One for making a form-data request in React Native, and one for parsing that request on server side. I will be using Vercel Serverless Funtions on the server side to give you an example, but all the steps you are going to follow in this post are applicable to other services like AWS Lambda, Netlify Functions, or etc. This should also be noted that: Due to the limitations of AWS Lambda, which is the underlying infrastructure of most of those services including Vercel Serverless Functions, the maximum payload size for the request body is 5 MB. So I strongly discourage you from using this method for uploading large files or videos. This post is meant to show you how to make a form-data request and how to handle that request in a serverless environment. If you need a complete media solution, you should look into services like AWS S3, Cloudinary, or Firebase Cloud Storage. Even with those services, you still might need to follow the first two steps for React Native. With that being said, let's get started with the main course.

1. Selecting an Image

To be able to select an image we are going to use react-native-image-crop-picker. I won't go into details on how to install it, because it's not the main scope of this post. Just follow their instructions and you should be fine. And assuming you did, here's how our code looks like for now:

import * as React from "react";
import ImagePicker from "react-native-image-crop-picker";
import { Button } from "react-native";

const Screen: React.FC = () => {
  const onPressSelectImage = () => {
    ImagePicker.openPicker({
      width: 480,
      height: 480,
      cropping: true
    }).then((image) => {
      console.warn(image.path);
    });
  };

  return <Button title="Select Image" onPress={onPressSelectImage} />;
};

export default Screen;
Enter fullscreen mode Exit fullscreen mode

2. Making a Request

Regular fetch packages causes problems on Android with multipart/form-data requests. Therefore we are going to use rn-fetch-blob, even though it's a more comprehensive library than what we're going to use it for. Again, you can follow installation instructions on their GitHub repo. Here's how your code should look like now:

import * as React from "react";
import ImagePicker from "react-native-image-crop-picker";
import RNFetchBlob from "rn-fetch-blob";
import { Button, Platform } from "react-native";

const fetchWithImage = async (imagePath: string) => {
  const body = [
    {
      name: "my_image",
      filename: Date.now().toString(),
      data: RNFetchBlob.wrap(Platform.OS === "android" ? imagePath : imagePath.replace("file://", ""))
    }
  ];

  const response = await RNFetchBlob.fetch(
    "POST",
    "https://example.com/example",
    {
      "Content-Type": "multipart/form-data"
    },
    body
  );

  return await response.json();
};

const Screen: React.FC = () => {
  const onPressSelectImage = () => {
    ImagePicker.openPicker({
      width: 480,
      height: 480,
      cropping: true
    }).then((image) => {
      fetchWithImage(image.path);
    });
  };

  return <Button title="Select Image" onPress={onPressSelectImage} />;
};

export default Screen;
Enter fullscreen mode Exit fullscreen mode

We wrap our image with RNFetchBlob by providing the image path which we trim the "file://" part according to the current OS. "name" will be the object name we will recieve on server side, and "filename" is something we should temporarily provide a random string.

3. Handling the Request

The rest is easy. We are going to use a library called multiparty. It makes handling multipart/form-data requests effortless, especially in serverless functions since we can't use any middleware like we would do in an Express.js application. Here is an example with a barebone Vercel Serverless Function:

import multiparty from "multiparty";
import { NowRequest, NowResponse } from "@vercel/node";

export default (request: NowRequest, response: NowResponse) => {
  new multiparty.Form().parse(request, async (error, fields, files) => {
    const image = files.my_image[0];
    const imagePath = image.path;

    // Handle your business logic using imagePath

    response.status(200).send("OK");
  });
};
Enter fullscreen mode Exit fullscreen mode

We recieved our file with the name we specified in the previous step. From there, you can use imagePath to handle your business logic whether it's uploading the file to other services or using it for something else.


I hope this was useful, you can also follow me on Twitter for future content:

twitter.com/oznbll

Discussion (0)