React Native - Making a POST Request with an Image from Image Picker
Tags: reactnative, tutorial, javascript, api
Published: 2023-03-31 21:53:33

## Introduction
[React Native Image Picker](https://github.com/react-native-image-picker/react-native-image-picker) is a popular React Native library used to capture images from the Camera and Photo Library of a users device. Commonly, the captured image needs to be used in the body of an API POST request. This would be the case if one wanted to gather predictions on the image from an online computer vision API or store the image in an external database, for example.

During this tutorial, we will look at the packages, tools and steps required for developers to convert the returned response from Image Picker into a suitable API request body.

## **Install the required packages**. 
For this tutorial, we will be using [axios](https://www.npmjs.com/package/react-native-axios) and [react native file system](https://www.npmjs.com/package/react-native-fs). We will run the following command in the root directory of your project to install these:
```
npm i react-native-axios && npm i react-native-fs
```
Install the cocoapods (if developing for iOS):
```
cd ios && pod install && cd ..
```

## Capturing the image

Setup Image Picker by following the installation instructions in the [Image Picker README](https://github.com/react-native-image-picker/react-native-image-picker). An image can be captured in a few ways: through the Camera or the Photo Library and with a callback or a promise. See examples [here](https://github.com/react-native-image-picker/react-native-image-picker#methods).

For example, using the Camera & callback method, our code can look something like this: 
```
import {launchCamera} from 'react-native-image-picker';

// callback method that handles response
const handleImageCapture = (response) => {
     if (response.didCancel) {
         console.log('User cancelled image picker');
     } else if (response.errorCode) {
         console.log(response.errorMessage);
     } else {
         // handle response
     }
};
    
const handleOpenCamera = () => {
    const options = {
      storageOptions: {
        path: 'images',
        mediaType: 'photo'
      },
    };
    launchCamera(options, handleImageCapture);
};
```
_Note that options can be edited based on use case, and the list of options is defined in the [README](https://github.com/react-native-image-picker/react-native-image-picker#options)._

Now, we want to get the URI of the image from the response in `handleImageCapture`. To do so, we will define a `useState` hook with a `capturedImageURI` variable and assign the image URI to it. Then, our code will look like this:
```
const [capturedImageURI, setCapturedImageURI] = useState('');
const handleImageCapture = (response) => {
    if (response.didCancel) {
        console.log('User cancelled image picker');
    } else if (response.errorCode) {
        console.log(response.errorMessage);
    } else {
        const source = response.assets![0]; //Unwrap the response assets and grab the first item (the captured image)
        setCapturedImageURI(source.uri!);
    }
};
```
`capturedImageURI` now holds the URI of the image.

## Converting the Image URI to base64
We can use the URI to display the image in the app, but we cannot pass it into the API request body. We need the **base64 representation** of the image. To do this, we will use `readFile` from react-native-fs to read the file from the URI. This is an example of what this code could look like:
```
import { readFile } from 'react-native-fs';

const loadImageBase64 = async (capturedImageURI) => {
  try {
    const base64Data = await readFile(capturedImageURI, 'base64');
    return 'data:image/jpeg;base64,' + base64Data;
  } catch (error) {
    console.error('Error converting image to base64:', error);
  }
};
```
The above function returns the base64 representation of the image.

## Making the API request with the base64 image
Now, we are finally ready to make the API request. Using axios, a common API request library for react and react-native, we will pass our base64 image into the body of the request and return its result:
```
const base64Image = await loadImageBase64(capturedImageURI);
axios({
    method: 'POST',
    url: 'https://example_api/endpoint',
    params: {
      api_key: 'YOUR_API_KEY'
    },
    data: base64Image,
    headers: {
      // define your headers
    }
  }).then(function (response) {
    console.log(response.data);
    return response.data;
  }).catch(function (error) {
    console.log(error.message);
    return null;
  });
```

## Summary
1. Use React Native Image Picker to capture an image.
2. Use the image URI and react-native-fs to convert the image into its base64 representation.
3. Pass the base64 representation into the body of the axios API request, and return the result.

## Other thoughts
**- What if I don't want to use axios?**
We can accomplish the same API request functionality without using axios. Instead, we can use the built-in fetch() function: 
```

fetch('https://example_api/endpoint?api_key=YOUR_API_KEY', {
  method: 'POST',
  body: base64Image
})
.then(function(response) {
  if (response.ok) {
    return response.json();
  } else {
    throw new Error('Request failed.');
  }
})
.then(function(data) {
  console.log(data);
  return data;
})
.catch(function(error) {
  console.log(error.message);
  return null;
});
```
Note that we need to pass the API key as a URL parameter instead of in the params.

**- Image Picker provides a base64 return value, so why do I need to convert the URI?**
The base64 return value that is returned from Image Picker is not in the right format for an API request body. At the very least, `'data:image/jpeg;base64,'` needs to be prepended to the base64 representation. During the time writing this, there are bugs involved in this approach, which is why it is suggested to explicitly load the base64 image using the URI and react-native-fs as done in the `loadImageBase64` function above. Also, this function can be used for URI's received from other sources, not just Image Picker.

**- How do I get the URI for an image on local disk (not through Image Picker)?**
To get the URI from a file in your project directory, you must use the require() function to load the image and get its URI. Here is example code:
```
const image = require('./images/myimage.png');
const imageUri = Image.resolveAssetSource(image).uri;
console.log(imageUri); // output the URI to the console
```
The `Image.resolveAssetSource()` function returns the URI and more information about the image. One can then extract the URI and store it in a variable.

## Conclusion
I hope this tutorial has been informative and helped provide the necessary steps to make a POST request with an image from React Native Image Picker.