React native image crop picker network issue .... on api hit with axios - react-native

Ios working fine
Android = network issue
I am stuck from so many days
RN version = 0.63.4
Rn crop picker version = 0.36.1
From R&D
I did all sloution like
upgarde flipper version
comment flipper line = android/app/debug/flipeerfile
Here i am attatching code of axios , image uploading file
axios code =
// import axios from "axios";
// import { SiteUrl } from '../config/Setting';
// var instance = axios.create({
// baseURL: 'http://192.168.1.90:3000/api/v1/user-service/users/',
// timeout: 60000,
// headers: {
// 'Content-Type': 'application/json',
// 'Access-Control-Allow-Origin': '*',
// 'Access-Control-Allow-Headers': '*',
// },
// });
// instance.interceptors.request.use(function (config) {
// console.log('config is ',config)
// return config;
// }, function (error) {
// return error;
// });
// instance.interceptors.response.use(function (response) {
// // console.log('response of axios',response)
// return response;
// }, function (error) {
// console.log('error of axios',error)
// return error;
// })
// export default instance;
import AsyncStorage from '#react-native-async-storage/async-storage';
import axios from 'axios';
import {SiteUrl} from '../config/Setting';
function parseError(messages) {
// error
// console.log('message',messages)
if (messages) {
if (messages instanceof Array) {
return Promise.reject({messages: messages});
} else {
return Promise.reject({messages: [messages]});
}
} else {
return Promise.reject({messages: ['エラーが発生しました']});
}
}
/**
* parse response
*/
function parseBody(response) {
// if (response.status === 200 && response.data.status.code === 200) { // - if use custom status code
// if (response.status === 200) {
return response;
// return response.data.result
// } else {
// console.log('message',response)
// return this.parseError(response.data)
// }
}
/**
* axios instance
*/
let instance = axios.create({
baseURL: 'http://14.98.110.243:3000/api/v1/user-service/users/',
paramsSerializer: function (params) {
return qs.stringify(params, {indices: false});
},
});
// request header
instance.interceptors.request.use(
async config => {
console.log('config is = ', config);
// Do something before request is sent
let apiToken = '';
apiToken = await AsyncStorage.getItem('apiToken');
console.log('apiToken', apiToken);
config.headers = {
Authorization: `Bearer ${JSON.parse(apiToken)}`,
'Content-Type': 'multipart/form-data',
};
return config;
},
error => {
return Promise.reject(error);
},
);
// response parse
instance.interceptors.response.use(
response => {
return parseBody(response);
},
error => {
// console.warn('Error status', error.response.status)
// return Promise.reject(error)
if (error.response) {
return parseError(error.response.data);
} else {
return Promise.reject(error);
}
},
);
export default instance;
Here is file code =
i am using hooks ... and i want to store multiple image in array with path
const [images, setImages] = useState([]);
const image = await ImagePicker.openPicker({
height: 385,
maxFiles: 6,
minFiles: 3,
mediaType: 'photo',
multiple: true,
width: 1000,
}).then(image => {
console.log('imahge', image);
let images = [];
images = images;
image.forEach((ele, i) => {
images.push(ele.path);
});
setImages(images);
console.log('all', images);
});
} catch (error) {
console.log('Error:', error);
}
```

not an expert, but where are you calling the method to upload the image. I had these issue of "Network Error" using Fetch and solved it using a Form Data object. Here's my code:
ImagePicker.openPicker({
multiple: true,
forceJpg: true,
maxFiles: 5,
compressImageQuality: 0.5,
mediaType: 'photo'
})
.then(images =>{
//map of around the pictures and return a form data that will be passed to whole.js
images.map((item, index) => {
this.setState({numberImages: this.state.numberImages + 1})
this.state.formData.append("photo", {
uri: item.path,
type: "image/jpeg",
name: `pickedImage-${index}.jpg`
})
});
});

finally i got an answer actually my backend team use a package that want mime type also in image object ...
so when i send that it working fine ...
for eg =>
this.state.formData.append("photo", { uri: item.path, mime:"image/jpeg", type: "image/jpeg", name: `pickedImage-${index}.jpg` })

Related

How to upload a file in react-native iOS?

While trying to upload a file I ran into an issue on iOS, the code works fine on android. After a bit of googling, I found that it is a known issue in react-native iOS and has a bug report submitted. This is the issue. I want to know if there is any other way to upload files on iOS. Below is the snippet of code I'm using. Please let me know if there is something that can be done.
const resp = await fetch(uploadUrl, {
method: 'POST',
headers: {
'content-type': 'multipart/form-data',
},
body: file, // file is File type
});
You can something like below code snippet
function uploadProfileImage(image, token) {
const url = ServiceUrls.UPLOAD_PROFILE_IMAGE
return uploadResourceWithPost({
url,
authToken: token,
formData: createFormData(image),
})
}
const createFormData = (data) => {
const form = new FormData()
form.append('file', {
uri: Platform.OS === 'android' ? data.uri : data.uri.replace('file://', ''),
type: 'image/jpeg',
name: 'image.jpg',
})
return form
}
const uploadResourceWithPost = ({ url, authToken, formData }) => {
return handleResponse(axios.post(url, formData, defaultUploadOptions(authToken)))
}
const defaultUploadOptions = (authToken) => ({
timeout,
headers: {
'X-Auth-Token': authToken,
'Content-Type': 'multipart/form-data',
},
})
const handleResponse = (responsePromise) => {
return NetInfo.fetch().then((state) => {
if (state.isConnected) {
return responsePromise
.then((response) => {
return ResponseService.parseSuccess(response)
})
.catch((error) => {
return ResponseService.parseError(error)
})
}
return {
ok: false,
message: 'Check your network connection and try again.',
status: 408,
}
})
}
const parseSuccess = ({ data, headers }) => ({ ...data, headers, ok: true })
const parseError = ({ response }) => {
let message = 'Check your network connection and try again.'
let status = 408
if (response && response.data) {
const { data } = response
message = data.message
status = data.code
}
return { status, message }
}

Mobile project with expo and hapi.js

Im strugglling with an error that im not capable of get a solution and i dont know if its happening in the front or in the back of the app.
Im trying to follow a tutorial where the guy is setting up an app that records your voice and return it as text from Google API speech to text.
this is the front part, the app is failing in the axios.post, the request is not passing and keeps loading until the error log says it cannot connect to the path.
import React, { Component } from 'react'
import {
StyleSheet, Text, View, TouchableOpacity, ActivityIndicator, Platform,
} from 'react-native'
// import { Audio, Permissions, FileSystem } from 'expo'
import * as Permissions from 'expo-permissions'
import { Audio } from 'expo-av'
import * as FileSystem from 'expo-file-system';
import axios from 'axios'
const styles = StyleSheet.create({
container: {
marginTop: 40,
backgroundColor: '#fff',
alignItems: 'center',
},
button: {
backgroundColor: '#1e88e5',
paddingVertical: 20,
width: '90%',
alignItems: 'center',
borderRadius: 5,
padding: 8,
marginTop: 20,
},
text: {
color: '#fff',
}
})
/*this.recordingSettings = JSON.parse(JSON.stringify(Audio.RECORDING_OPTIONS_PRESET_HIGH_QUALITY = */let recordingOptions = {
android: {
extension: '.m4a',
outputFormat: Audio.RECORDING_OPTION_ANDROID_OUTPUT_FORMAT_MPEG_4,
audioEncoder: Audio.RECORDING_OPTION_ANDROID_AUDIO_ENCODER_AAC,
sampleRate: 44100,
numberOfChannels: 2,
bitRate: 128000,
},
ios: {
extension: '.m4a',
outputFormat: Audio.RECORDING_OPTION_IOS_OUTPUT_FORMAT_MPEG4AAC,
audioQuality: Audio.RECORDING_OPTION_IOS_AUDIO_QUALITY_HIGH,
sampleRate: 44100,
numberOfChannels: 2,
bitRate: 128000,
linearPCMBitDepth: 16,
linearPCMIsBigEndian: false,
linearPCMIsFloat: false,
},
};
export default class SpeechToTextButton extends Component {
constructor(props) {
super(props)
this.recording = null
this.state = {
isRecording: false,
//we would like to know if data fetching is in progress
isFetching: false,
//we will write the transcript result here
transcript: '',
}
}
startRecording = async () => {
// request permissions to record audio
const { status } = await Permissions.askAsync(Permissions.AUDIO_RECORDING)
// if the user doesn't allow us to do so - return as we can't do anything further :(
if (status !== 'granted') return
// when status is granted - setting up our state
this.setState({ isRecording: true })
// basic settings before we start recording,
// you can read more about each of them in expo documentation on Audio
await Audio.setAudioModeAsync({
allowsRecordingIOS: true,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: true,
})
const recording = new Audio.Recording()
try {
// here we pass our recording options
await recording.prepareToRecordAsync(recordingOptions)
// and finally start the record
await recording.startAsync()
console.log('funcionaaa')
} catch (error) {
console.log(error)
// we will take a closer look at stopRecording function further in this article
this.stopRecording()
console.log('no funca')
}
// if recording was successful we store the result in variable,
// so we can refer to it from other functions of our component
this.recording = recording
}
stopRecording = async () => {
// set our state to false, so the UI knows that we've stopped the recording
this.setState({ isRecording: false })
try {
// stop the recording
await this.recording.stopAndUnloadAsync()
console.log('aca tiene que parar')
} catch (error) {
console.log(error)
}
}
getTranscription = async () => {
// set isFetching to true, so the UI knows about it
this.setState({ isFetching: true })
try {
// take the uri of the recorded audio from the file system
const { uri } = await FileSystem.getInfoAsync(this.recording.getURI())
// now we create formData which will be sent to our backend
const formData = new FormData()
formData.append('file', {
uri,
// as different audio types are used for android and ios - we should handle it
type: Platform.OS === 'ios' ? 'audio/x-wav' : 'audio/m4a',
name: Platform.OS === 'ios' ? `${Date.now()}.wav` : `${Date.now()}.m4a`,
})
// post the formData to our backend
const { data } = await axios.post('http://190.19.68.120/api/speech', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
})
console.log(data)
// set transcript from the data which we received from the api
this.setState({ transcript: data.transcript })
} catch (error) {
console.log('There was an error reading file', error.request)
this.stopRecording()
// we will take a closer look at resetRecording function further down
this.resetRecording()
}
// set isFetching to false so the UI can properly react on that
this.setState({ isFetching: false })
}
deleteRecordingFile = async () => {
// deleting file
try {
const info = await FileSystem.getInfoAsync(this.recording.getURI())
await FileSystem.deleteAsync(info.uri)
} catch (error) {
console.log('There was an error deleting recorded file', error)
}
}
resetRecording = () => {
this.deleteRecordingFile()
this.recording = null
}
handleOnPressOut = () => {
// first we stop the recording
this.stopRecording()
console.log('para en el pressout')
// second we interact with our backend
this.getTranscription()
}
render() {
const {
isRecording, transcript, isFetching,
} = this.state
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPressIn={this.startRecording}
onPressOut={this.handleOnPressOut}
>
{isFetching && <ActivityIndicator color="#ffffff" />}
{!isFetching &&
<Text style={styles.text}>
{isRecording ? 'Recording...' : 'Start recording'}
</Text>
}
</TouchableOpacity>
<Text>
{transcript}
</Text>
</View>
)
}
}
Here it is the back part, where i receive the request from the front and send the audio to the google API
'use strict';
const Hapi = require('#hapi/hapi');
const fs = require('fs')
const axios = require('axios')
const speech = require('#google-cloud/speech');
const ffmpeg = require('fluent-ffmpeg');
const client = new speech.SpeechClient();
const init = async () => {
const server = Hapi.server({
port: 3005,
host: 'localhost'
});
server.route({
method: 'POST',
path: '/speech',
config: {
handler: async (request, h) => {
const data = request.payload;
console.log(data)
if (data.file) {
const name = data.file.hapi.filename;
const path = __dirname + "/uploads/" + name;
const encodedPath = __dirname + "/uploads/encoded_" + name;
const file = fs.createWriteStream(path);
file.on('error', (err) => console.error(err));
data.file.pipe(file);
return new Promise(resolve => {
data.file.on('end', async (err) => {
const ret = {
filename: data.name,
headers: data.file.hapi.headers
}
ffmpeg()
.input(path)
.outputOptions([
'-f s16le',
'-acodec pcm_s16le',
'-vn',
'-ac 1',
'-ar 41k',
'-map_metadata -1'
])
.save(encodedPath)
.on('end', async () => {
const savedFile = fs.readFileSync(encodedPath)
const audioBytes = savedFile.toString('base64');
const audio = {
content: audioBytes,
}
const sttConfig = {
enableAutomaticPunctuation: false,
encoding: "LINEAR16",
sampleRateHertz: 41000,
languageCode: "en-US",
model: "default"
}
const request = {
audio: audio,
config: sttConfig,
}
const [response] = await client.recognize(request);
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
fs.unlinkSync(path)
fs.unlinkSync(encodedPath)
resolve(JSON.stringify({ ...ret, transcript: transcription }))
})
})
})
}
},
payload: {
output: 'stream',
parse: true,
}
}
})
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
});
init();
i thought i could try migrating the server to express.js but under handler, i got payload key, and i dont know what to do with that in an express server.

How to use axios to upload image from imagePicker

I trying to upload a file image to API in postman thats work fine but when a i try file image from ImagePicker didnot work.
I think doing something wrong when create formdata
Handler
ImagePicker.showImagePicker(optionsImagePicker, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
// const source = { image: response.data };
let photo = { uri: response.uri}
let formdata = new FormData();
formdata.append("product[name]", 'test')
formdata.append("product[price]", 10)
formdata.append("product[category_ids][]", 2)
formdata.append("product[description]", '12dsadadsa')
formdata.append("product[images_attributes[0][file]]", {uri: photo.uri, name: 'image.jpg', type: 'image/jpeg'})
updateProfilePic(formdata)
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
// this.setState({
// avatarSource: source,
// });
}
});
Service
export function uploadImageProfile(data: any): Promise<any> {
const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
};
return api.post('/users/profilepic', {image: data}, config).then((res) => {
console.log(res.data);
return res.data;
});
}
Your form data must be like that.
formdata.append('file',{
uri: Platform.OS === 'android' ? photo.uri : 'file://' + photo.uri,
name: 'test',
type: 'image/jpeg' // or your mime type what you want
});
Then
axios.post('/users/profilepic', formdata, config).then((res) => {
console.log(res.data);
return res.data;
});
let formdata = new FormData();
formdata.append('file',{
uri: Platform.OS === 'android' ? photo.uri : 'file://' + photo.uri,
name: 'test',
type: 'image/jpeg'
});
use method:"POST" and spread formdata.getHeaders() into header
let reqObj = {
method: "POST",
url: 'http://example.com/upload/image',
headers: {
'x-sh-auth': token,
...formdata.getHeaders()
},
maxContentLength: Infinity,
maxBodyLength: Infinity
};
axios(reqObj).then(result => {
console.log(result)
}).catch(error => {
console.log(error)
});
I changed how I send image to the server. Now send im base64 and in server convert to file with fs.
const uploadImage = {
imageBase64: 'data:' + response.type + ';base64,' + response.data,
};
updateProfilePic(uploadImage);
server side
async saveImageProfile(imageBase64, logedUserData) {
let base64Image = imageBase64.imageBase64.split(';base64,').pop();
let type = imageBase64.imageBase64.split('image/').pop().split(';')[0];
let newFileName = `${logedUserData.id}.${type}`;
if (imageFileFilter(type)) {
const file = await fs.writeFile('./files/' + newFileName, base64Image, { encoding: 'base64' }, function (err) {
console.log('File created');
});
const url = `${baseUrl}/users/files/${newFileName}`;
this.updateRefProfilePic(url, logedUserData);
}
else {
throw new BadRequestException("Tipo de arquivo não suportado");
}
}

Too many requests when controlling spinner show/hide from axois interceptors

I have an SPA written in Vue (Webpack) where I want to control the visibility of a spinner based on whether or not the app is currently handling an HTTP request or a response.
Following some tutorials, I came up with the event bus scheme and did this:
Created eventBus.js:
import Vue from 'vue';
export const eventBus = new Vue();
I'm setting my axios interceptors in the created() hook of App.vue. Here's what the necessary functions look like in that component:
data() {
return {
showLoader: false
};
},
created(){
this.setAxiosInterceptors();
// some code removed //
}
},
mounted() {
eventBus.$on('show-loader', () => {
this.showLoader = true;
});
eventBus.$on('hide-loader', () => {
this.showLoader = false;
});
},
methods: {
setAxiosInterceptors() {
var tokenCookieName = this.$store.getters.getCookieNames.apiToken;
var cookieDefaultValue = this.$store.getters.getCookieDefaultValue;
// token expired middleware
this.axios.interceptors.response.use(response => {
var data = response.data;
if(data.info.api_token) {
this.$cookie.set(tokenCookieName, data.info.api_token);
}
if(data.status == 'error' && data.info.login_failed) {
this.$cookie.set(tokenCookieName, cookieDefaultValue);
window.location = '/'; // not possible to use Vue router here
}
eventBus.$emit('hide-loader');
return response;
},
error => {
eventBus.$emit('hide-loader');
console.log('Response interception failed!');
return Promise.reject(error);
});
// attach API token middleware
this.axios.interceptors.request.use(config => {
var apiToken = this.$cookie.get(tokenCookieName);
if (!apiToken) {
apiToken = cookieDefaultValue;
}
config.headers.Authorization = 'Bearer ' + apiToken;
eventBus.$emit('show-loader');
return config;
},
error => {
eventBus.$emit('hide-loader');
console.log('Request interception failed!');
return Promise.reject(error);
}
);
}
}
Please ignore some of the code that isn't relevant to the problem, but I wanted to show how things are set up. Problem is, as soon as I visit my home page, the app keep making the startup GET requests over and over, until my server returns a 429 error.
Interestingly, in my eventBus.$on handlers, if I just do a console.log, this behavior doesn't appear (of course, the spinner doesn't work as well) but as soon as I change a variable or call a vuex action, this infinite reloading starts.
Any clue?
In the main.js file
Vue.prototype.$axios = axios.create(
{
headers:
{
'Content-Type': 'application/json',
},
baseURL: process.env.API_URL
}
);
Vue.prototype.$axios.interceptors.request.use(
config =>
{
eventBus.$emit('show_spin');
let token = getTokenID();
if(token && token.length) config.headers['Authorization'] = token;
return config;
},
error =>
{
eventBus.$emit('hide_spin');
if (error.status === 401) VueRouter.push('/login');
else throw error;
}
);
Vue.prototype.$axios.interceptors.response.use(
response =>
{
eventBus.$emit('hide_spin');
return response;
},
error =>
{
eventBus.$emit('hide_spin');
return new Promise(function(resolve,reject)
{
if (error.config && error.response && error.response.status === 401 && !error.config.__isRetry)
{
myVue.refreshToken(function()
{
error.config.__isRetry = true;
error.config.headers['Authorization'] = getTokenID();
myVue.$axios(error.config).then(resolve,reject);
},function(flag) // true = invalid session, false = something else
{
if(process.env.NODE_ENV === 'development') console.log('Could not refresh token');
if(getUserID()) myVue.showFailed('Could not refresh the Authorization Token');
reject(flag);
});
}
else throw error;
});
}
);
let myVue = new Vue(
{
el: '#app',
data: function()
{
return {
spin_visible: 0, // dynamically show/hide spinner
};
},
created: function()
{
eventBus.$on('show_spin', this.showSpin);
eventBus.$on('hide_spin', this.hideSpin);
},
methods:
{
showSpin: function()
{
this.spin_visible++;
},
hideSpin: function()
{
if(this.spin_visible>0) this.spin_visible--;
},
....
and then in App.vue
<template>
<router-view/>
<div class="spinner" v-show="$root.spin_visible">
<!-- define your spinner here -->
</div>
</template>

Upload image using fetch doesn't work in React Native (iOS)

I am working on a mobile app using React Native and posting an image on iOS doesn't work. I have hooked up my code to requestbin, setup the info.plist to allow non-https urls and other post requests are working (e.g login). For the image, all I get is a blank body for the request. Here is the code posting the image:
uploadImage = () => {
const data = new FormData();
data.append('photo', {
uri: this.state.logo.uri,
name: 'logo'
});
fetch([requestbin url here], {
method: 'post',
body: data
}).then(res => {
console.log(res);
});
for the image, I am using react-native-image-picker to get it and store it in state under the variable 'logo'. Here is that code as well
handleNewImage = () => {
var options = {
title: 'Choose new company logo',
storageOptions: {
skipBackup: true,
path: 'images'
}
};
showImagePicker(options, response => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
} else {
let source = { uri: response.uri };
// You can also display the image using data:
// let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
logo: source
});
}
});
Remember that you also should pass a name key too, like below:
let url = "",
headers = "",
method = "POST",
body = new FormData(),
uri = "URI of the picked image.";
body.append("photo", {
name: "Just a name",
uri : Platform.OS === "android" ? uri : uri.replace("file://", "")
}
);
fetch(url, method, headers, body)
.then(function (response) {
})
.catch(function (error) {
});
function uploadProfilePicture(mImage) {
var data = new FormData();
data.append('theFile', { uri: mImage.uri, name: 'profile_photo.jpg', type: 'image/jpg' });
fetch(AppConstant.BASE_URL + AppConstant.upload_media, {
method: 'POST',
body: data
})
.then((response) => response.json())
.then((responseJson) => {
var err = 'error_message' in responseJson ? true : false
if (err) {
alert(responseJson.error_message)
} else {
alert(JSON.stringify(responseJson))
}
})
.catch((error) => {
console.error(error);
alert(error)
});
}
If anyone has issues with using fetch in iOS, check out react-native-file-upload I have found it to be extremely helpful in both image uploading and regular posts.