A React Native application is designed to upload photos to the Cloudinary server and retrieve a link for the uploaded photo. The process involves two steps where the file from the Image Picker is first uploaded to the app server:
import {DBStorageInteractor} from '../interfaces';
import {BASE_URL} from '../../../config/constants';
import ImageResizer from 'react-native-image-resizer';
import {ImagePickerResponse} from 'react-native-image-picker';
async uploadImage(photo: ImagePickerResponse, id: string): Promise<string> {
return new Promise<string>(async (resolve, reject) => {
if (!photo) {
reject(Error('Photo is not presented'));
return;
}
this.getBody(photo, id)
.then((body) => {
const headers = {
Accept: 'application/json',
'Content-Type': 'application/json',
};
const options = {
method: 'POST',
body: body,
headers: headers,
};
fetch(`${BASE_URL()}/api/images/upload`, options)
.then((response) => response.json())
.then((response) => {
const secureUrl = response.secure_url;
console.log('Uploaded successfully. Url=', secureUrl);
resolve(secureUrl);
})
.catch((error) => {
const message = `Failed uploading. Error=${error}`;
console.log(message);
reject(Error(message));
});
})
.catch((error) => {
reject(error);
});
});
}
getBody(photo: ImagePickerResponse, id: string): Promise<string> {
return new Promise((resolve, reject) => {
if (photo.fileSize < 100000) {
resolve(
JSON.stringify({
img: photo.data,
name: `eMia${id}.${this.getFileExtension(photo.uri)}`,
})
);
} else {
ImageResizer.createResizedImage(photo.uri, 400, 400, 'JPEG', 80)
.then(({uri}) => {
RNFS.readFile(uri, 'base64')
.then((data) => {
resolve(
JSON.stringify({
img: data,
name: `eMia${id}.${this.getFileExtension(photo.uri)}`,
})
);
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
}
});
}
getFileExtension(filename) {
return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
}
Figure 1 illustrates how the client side of the app uploads photos from the Image Picker to the server side and receives a link to the uploaded photo.
In the second step, the server-side code written in NodeJS handles the request in two stages. Firstly, it saves the image file from the request to a temporary directory and then proceeds to upload it to the Cloudinary server:
const {Router} = require('express')
const router = Router()
const cloudinary = require('cloudinary').v2;
const fs = require('fs')
router.post('/upload', async (req, res) => {
try {
const file = req.body.img;
const name = req.body.name;
const path = `tmp/${name}`;
fs.writeFile(path, file, 'base64', (err) => {
if (err) {
console.log(err);
throw err
}
cloudinary.uploader.upload(path)
.then((results) => {
res.status(200).json(results)
})
.catch((error) => {
res.status(400).json(error)
});
})
} catch (error) {
res.status(500).json(error)
}
}
)
Figure 2 portrays the handling of the '/upload' request on the NodeJS server.
To configure Cloudinary on the server side, you need to include the following code:
const cloudinary = require('cloudinary').v2;
require('dotenv').config();
cloudinary.config({
cloud_name: process.env.cloud_name,
api_key: process.env.api_key,
api_secret: process.env.api_secret,
});
The '.env' file located in the project's root folder contains the necessary parameters as follows:
cloud_name=<Cloudinary cloud name>
api_key=<API key from the Cloudinary project settings>
api_secret=<API secret from the Cloudinary project settings>