react native base64 image upload fail with status code 400 - reactjs

I want to upload my image as base 64 to the server, after user pick image it stores as base64 in state and then I call upload function but it give me this error: request failed with status code 400.
I need to first call an API and it takes user id and respond with an upload name id, then I call upload image API
here is my implementation:
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
base64: true
});
setImage(result)
};
const uploadImagetoServer = async (userId) => {
let uploadId;
try {
const response = await axios
.post('URL', {
"id": userId
});
console.log('id res', response.data);
uploadId = response.data;
} catch (error) {
console.log(error.message);
}
try {
const response = await axios
.post('ANOTHER_URL', {
headers: {
'Content-Type': 'application/json'
},
"fileName": uploadId,
"fileBase64String": image.base64,
"folderName": "Users",
"fileExtension": ".jpg"
});
console.log('upload res', response.data);
} catch (error) {
console.log(error.message);
}
}
const allowAccess = async () => {
if (Platform.OS !== 'web') {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
} else {
pickImage()
.then(() => {
uploadImagetoServer(userData.id)
})
}
}
}
anyone can help me with this? ty

you need to add contentType in headers
'Content-Type': `multipart/form-data;`,
here is an example
npm install --save form-data
import FormData from 'form-data'
let data = new FormData();
data.append('file', file, file.name);
return (dispatch) => {
axios.post(URL, data, {
headers: {
'accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.8',
'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
}
})
.then((response) => {
//handle success
}).catch((error) => {
//handle error
});
};}

Related

Send Multiple Data With Axios

I have a problem , my problem is when i send multiple data with axios , the image in formdata dosen't send , but when i send only the formdata it works , if any know how to send multiple data ins axios just give me what's the solution
const onSubmit = async (data) => {
if(loading) return ;
setLoading(true);
const formData = new FormData();
formData.append("image",image);
let details = {
name:data.name,
image:formData,
price:data.price,
description:convertToRaw(editorState.getCurrentContent()).blocks[0].text,
qty:data.qty,
promo:data.oldPrice,
categorie:data.categorie,
// images:[image,image2,image3,image4]
}
try{
let config = {
headers:{
authorization:"Authorization Token "+jwt,
"Accept": "application/json",
"Content-Type": "multipart/form-data",
}
}
await axios.post('../../api/products',details,config)
.then(res => console.log(res.data))
.then(setLoading(false))
.catch(err => console.log(err))
}catch(err){
console.log(err);
}
}
I would do something like this while uploading with images:
const onSubmit = async (data) => {
if(loading) return ;
setLoading(true);
const formData = new FormData();
formData.append("image",image);
let details = {
name:data.name,
price:data.price,
description:convertToRaw(editorState.getCurrentContent()).blocks[0].text,
qty:data.qty,
promo:data.oldPrice,
categorie:data.categorie
}
for (let key in details) {
formData.append(key, details[key]);
}
try{
let config = {
headers:{
authorization:"Authorization Token "+jwt,
"Content-Type": "multipart/form-data",
}
}
await axios.post('../../api/products',formData ,config)
.then(res => console.log(res.data))
.then(setLoading(false))
.catch(err => console.log(err))
}catch(err){
console.log(err);
}
}

Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'uri.split')]on React Native Expo

I got a problem when upload image on react native
and here is my code
_pickImage = async () => {
await Permissions.askAsync(Permissions.CAMERA_ROLL);
const { cancelled, uri } = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 4],
base64: true
});
if (!cancelled) this.setState({ ImageKTP: uri });
this.createFormData();
};
and here is createFormData
createFormData = async (uri) => {
const {ImageKTP} = this.state;
let imageUri = uri.split('.');
let fileType = uriParts[uriParts.length - 1];
let formData = new FormData();
formData.append('ImageKTP', {
imageUri,
name: `ImageKTP.${fileType}`,
type: `image/${fileType}`,
});
fetch('http://192.168.0.20/profile.php?ImageKTP=' + ImageKTP,{
method: 'POST',
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
body: formData
})
.then((response) => response.json())
.then((responseJson) =>{
alert(responseJson);
})
.catch((error)=>{
console.error(error);
});
};
Any Solution for this? I still dont get it how to get the uri
Thank you
You need to call createFromData only when you successfully have uri set
if (!cancelled) {
this.setState({ ImageKTP: uri }, () => {
this.createFormData();
});
}
createFormData = async uri => {
const { ImageKTP } = this.state;
if (!ImageKTP) return;
/** Your processing code... */
};

How do I create a Generic postToAPI(route, package2send) function in React?

In our project we are using the MERN stack
I want to create a generic function whose input is the path to any api endpoint in our server and the JSON package to POST to the server. I want it to return the JSON sent back from the server.
That way when we are developing our mobile app and web app, we can simply use this function for all of our api endpoint POSTs.
I'm very new to using React/React-Native so I'm sure that I'm not understanding some sort of key concept.
Here is what I have so far:
import React from 'react';
// returns whatever the respective apiEndpoint is suppose to return
function postToAPI(route, package2send)
{
async() =>
{
try
{
const payload = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: package2send
}
const res = await fetch(route, payload);
console.log(res);
const data = await response.json();
console.log(data);
return data;
}
catch(error)
{
console.error(error);
}
}
}
export default postToAPI;
Whenever I call this function from my Login.js after I
import { postToAPI } from './postToAPI'
I get this error: 'TypeError: Object(...) is not a function'
I'm sure there are multiple things wrong with this code, so if someone could steer me in the right direction, it would be greatly appreciated.
If you export the function as default, you must import without bracket like that.
import postToAPI from './postToAPI';
If you would like to write a generic API call class, I advise you this class which I wrote before.
import { BASE_URL } from "../config";
import { Actions } from "react-native-router-flux";
import { deleteUserInfo } from "./SessionHelper";
const API_URL = BASE_URL;
class ApiHelper {
private accessToken?: string;
constructor() {
this.accessToken = undefined;
}
setAccessToken = (accessToken: string) => {
this.accessToken = accessToken;
};
getAccessToken = () => {
return this.accessToken;
};
getRequest = async (endpoint: string) => {
try {
const response = await fetch(`${API_URL}${endpoint}`, {
method: "GET",
headers: {
"x-access-token": `${this.accessToken}`
}
});
const responseJson = await response.json();
return responseJson;
} catch (error) {
console.error(error);
}
};
postRequest = async (endpoint: string, body: any) => {
try {
const response = await fetch(`${API_URL}${endpoint}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-access-token": `${this.accessToken}`
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
const finalResponse = { data: responseJson, status: response.status };
if (response.status === 401) {
deleteUserInfo();
this.accessToken = undefined;
Actions.auth();
}
return finalResponse;
} catch (error) {
console.error(error);
return error;
}
};
patchRequest = async (endpoint: string, body: any) => {
try {
const response = await fetch(`${API_URL}/${endpoint}`, {
method: "PATCH",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-access-token": `${this.accessToken}`
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
const finalResponse = { data: responseJson, status: response.status };
if (response.status === 401) {
deleteUserInfo();
this.accessToken = undefined;
Actions.auth();
}
return finalResponse;
} catch (error) {
console.error(error);
}
};
deleteRequest = async (endpoint: string, body: any) => {
try {
const response = await fetch(`${API_URL}/${endpoint}`, {
method: "DELETE",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"x-access-token": `${this.accessToken}`
},
body: JSON.stringify(body)
});
const responseJson = await response.json();
const finalResponse = { data: responseJson, status: response.status };
if (response.status === 401) {
deleteUserInfo();
this.accessToken = undefined;
Actions.auth();
}
return finalResponse;
} catch (error) {
console.error(error);
}
};
}
export const APIHelper = new ApiHelper();

Generic function to request api with Axios

I am trying to build a generic function for my endpoints, using Axios and React. Generic because I have always the same header and I do not want to repeat a lot of code for each of my components.
To do that, I built this function (sorry, a lot of comments that I will remove after of course) :
export const getRequest = ( endpoint ) => axios
.get( env._URL_SERVER_ + endpoint, { headers: getHeaders() } )
.then((res) => {
// Success
console.log(res);
return {error: false, response: res.data};
})
.catch((error) => {
// Error
if (error.response) {
/*
* The request was made and the server responded with a
* status code that falls out of the range of 2xx
*/
console.log(error.response.data);
console.log(error.response.status);
return {error: true, status: error.response.status, data: error.response.data};
} else if (error.request) {
/*
* The request was made but no response was received, `error.request`
* is an instance of XMLHttpRequest in the browser and an instance
* of http.ClientRequest in Node.js
*/
console.log(error.request);
return {error: true, data: error.request };
} else {
// Something happened in setting up the request and triggered an Error
console.log('Error', error.message);
return {error: true, data: error.message}
}
});
Ant then in my components I do that :
getSchools = () => {
this.setState({
loadingSchools: true
}, () => {
getRequest(`/schools?name=${this.state.filterByName}&city=${this.state.filterByCity}&school_type_id=${this.state.filterBySchoolTypeId}&page=${this.state.selectedPage}`)
.then((response) => {
// there is an error
if (!response.error) {
this.setState({
schools: response.response.data,
meta: response.response.meta,
links: response.response.links
})
} else {
this.setState({
error: true,
errorMessage: response.data,
})
}
})
.then(() => {
this.setState({loadingSchools : false});
})
})
}
It works fine. I tested it in several situation (all is OK - 200, not found - 404, no response). But is it a good practice ? I feel that there is a lot of codes in the parent component. Maybe I complicate my life?
Here is how I've done it:
var URL_BACKEND = "http://localhost:5000/";
// Create Function to handle requests from the backend
callToBackend = async (ENDPOINT, METHOD) => {
const options = {
url: `${URL_BACKEND}${ENDPOINT}`,
method: METHOD,
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
};
const response = await axios(options);
return response.data;
}
// Then you make a call with the exact endpoint and method:
const response = await this.callToBackend('createSetupIntent', 'POST');
console.log(JSON.stringify(response));
create one common file for base URL let's say api.js
// api.js file code
export const apiUrl = axios.create({
baseURL: 'http://localhost:5000',
});
Register file
// register.js file code
import { apiUrl } from './api';
try {
const resp = await apiUrl.post('/api/register', {
username,
email,
password,
});
const { data, status } = resp;
if (Object.keys(data).length && status === 200) {
// received api data successfully
console.log('API response', data);
}
} catch (err) {
console.log(err);
}
// For auth request
try {
const token = localstorage.getItem('token');
const res = await apiUrl.post(
'/authroute',
{
name: fullName,
originCountry: country,
career: careerStatus,
},
{
headers: { Authorization: `Bearer ${token}` },
}
);
const { data, status } = strapiRes;
if (Object.keys(data).length && status === 200) {
return res.status(status).json(data);
}
} catch (error) {
throw new Error(error);
}
// same for all request
apiUrl.get(endpoint);
apiUrl.post(endpoint, body);
apiUrl.put(endpoint, body);
apiUrl.delete(endpoint, body);

How to send token through headers by using axios post method in react

In my react app i am using axios to perform the REST api requests.
But it's unable to send the Authorization header with the request.
Here is my code:
This is authentication.js
async login(data) {
try {
const res = await axios.post(`'http://localhost:5000'/api/login`, data);
this.subject.next(true);
return res;
} catch (error) {
throw error;
}
}
This is login.js
async handleSubmit(e) {
e.preventDefault();
try {
const res = await auth.login(this.state.data);
tokenService.saveToken(res.data.token);
this.setState({});
swal({
title: "Good job!",
text: "Login successfully!",
icon: "success",
});
}
catch (error) {
swal({
title: "incorrect or password!",
text: "Login failed!",
icon: "error",
});
}
}
You can use Axios to create an instance of it with the headers passed to it save in local storage. Then, use that instance to further make requests. In this way, you don't to include it in every request.
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
headers: {'Authorization': bearer <TOKEN_FROM_LOCALSTORAGE>}
});
Use the instance to make request
instance.get("users")
.then(res => {
console.log(res);
console.log(res.data);
})
You can use this instance and customize it according to your instance so that code won't repeat. For further reference
Store it in localstorage and then concatenate it with 'Bearer'
let bearer = 'Bearer ' + JSON.parse(localStorage.getItem('token'));
//payload is the data which you're trying to send to the api endpoint
axios({
method: 'post',
url: '/api-endpoint',
headers: {
Authorization: bearer
},
data: payload
})
.then(response => response.json())
.then(json => json)
.catch(error => {
throw error;
});
check if the user is authenticated to use the Get or Post requests made by them
isAuthenticated() {
const token = localStorage.getItem('token');
}
Use the token to make the post request
axios({
method: 'post',
url: ''http://localhost:5000'/api/login',
{ headers: {"authorization" : token} }
data: payload
}),
.then(response => response.json())
.then(json => json)
.catch(error => {
throw error;
});
Handle your login
async handleSubmit(e) {
e.preventDefault();
try {
const res = await auth.login(this.state.data);
tokenService.saveToken(res.data.token);
this.setState({});
swal({
title: "Good job!",
text: "Login successfully!",
icon: "success",
});
}
catch (error) {
swal({
title: "incorrect or password!",
text: "Login failed!",
icon: "error",
});
}
}
Why you don't use axios interceptors like this:
axiosInstance.interceptors.request.use(
config => {
config.headers.authorization = localStorage.getItem("token");
return config;
},
error => Promise.reject(error)
);
Or declared on https://github.com/axios/axios/issues/1383

Resources