Send Images from React Native to Serverless Functions
Tags: javascript, reactnative, serverless, node
Published: 2020-11-17 14:50:02

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](https://github.com/ivpusic/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:

```typescript
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;
```

###**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](https://github.com/joltup/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:

```typescript
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;
```

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](https://github.com/pillarjs/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:

```typescript
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");
  });
};
```

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](https://twitter.com/oznbll)