upload expo camera roll image to server - react-native

I'm using expo camera to take a picture. The output I get is a file in format file:///data/user/0/host.exp.exponent/..../Camera/1075d7ef-f88b-4252-ad64-e73238599e94.jpg
I send this file path to the following action and try to upload it to
export const uploadUserPhoto = (localUri,uid) => async dispatch => {
let formData = new FormData();
formData.append('avatar', { uri: localUri, fileName: uid});
let res = await fetch(`${API_URL}api/uploadPhoto`, {
method: 'POST',
body: formData,
header: {
'content-type': 'multipart/form-data',
},
});
Afterward, I get [Unhandled promise rejection: TypeError: Network request failed] and nothing arrives to server. I tried using some string to send in the body and the fetch worked, so I guess it has something to do with my formData configuration.
The formData is:
{
"_parts": Array [
Array [
"avatar",
Object {
"fileName": "6eAntcmoEsdBeSD2zfka9Nx9UHJ3",
"type": "jpg",
"uri": "file:///data/us....2e6e3e8d3223.jpg",
},
],
],
}
How I use postman to test my sails controller
Sails controller function:
uploadPhoto: function (req, res) {
req.file('avatar').upload({
adapter: require('skipper-s3'),
key: 'XXXX',
secret: 'XXX',
bucket: 'XXX',
saveAs: req.param('fileName') + '.png',
}, function (err, filesUploaded) {
....
});
});
}

Problem was that I didn't specify the filename.
Just did this and it worked!!! :)
data.append('filename', 'avatar');
data.append('fileName', uid);
data.append('avatar', {
uri: photo.uri,
name: 'selfie.jpg',
type: 'image/jpg'
});
const config = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
body: data
};
fetch(`${API_URL}api/uploadPhoto`, config).then(responseData => {
console.log(responseData);
}).catch(err => { console.log(err); });

just add these params in photo this worked for me
data.append('avatar', {
uri: photo.uri,
name: 'selfie.jpg',
type: 'image/jpg'
});

Related

Got error 422 with vuex (dispatch) in vuejs

I got an error :
422 (Unprocessable Content)
when I tried to post a data in register form
I have this in my Register.vue
methods: {
register() {
this.$store.dispatch('register', {
firstname: this.firstname,
lastname: this.lastname,
email: this.email,
password: this.password,
});
},
},
};
and in my vuex
actions: {
register(credentials) {
const requestOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
dataType: 'json',
body: JSON.stringify(credentials),
};
console.log(credentials);
return fetch('http://localhost/api/users', requestOptions)
.then((response) => {
return response.json;
})
.catch((err) => console.log(err.message));
},
}
Anyone know where I'm wrong ?
Many thanks
Don't return twice if the request is good.
actions: {
register(credentials) {
const requestOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
dataType: 'json', // not needed
body: JSON.stringify(credentials),
};
console.log(credentials);
return fetch('http://localhost/api/users', requestOptions) // first time
.then((response) => {
return response.json; // second time
})
.catch((err) => console.log(err.message));
},
}
Also use async/await. I'd do
actions: {
async register(credentials) {
const requestOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
dataType: 'json',
body: JSON.stringify(credentials),
};
const res = await fetch('http://localhost/api/users', requestOptions);
}
return res.json();
}
And in the Register.vue
methods: {
register() {
this.$store.dispatch('register', {
firstname: this.firstname,
lastname: this.lastname,
email: this.email,
password: this.password,
}).then(data => {
console.log(data)
}).catch((err) => console.log(err.message));
});
},
};
Also you can put it in try/cache etc. It's up to you.
Check the docs, it well explained.

How to get stored path of uploaded image in Vue / October

I have an app that uses October CMS to store images in a database. When I add the image in October, I use the following method:
Which gives me the image_path in October:
public $attachOne = [
'image' => ['System\Models\File']
];
public function getImagePathAttribute(){
return $this->image->path;
}
http://localhost/bit703/module6/storage/app/uploads/public/60b/6cb/8d3/60b6cb8d39915448328696.jpg
The problem I'm having is that when I upload my image from Vue, it's storing it without the path of where the image is being stored, causing errors in the October backend.
Is there a way to find that image path and add it to my request in Vue? My Vue code looks as follows:
<script>
import axios from 'axios';
export default {
data() {
return {
apiRequest: new this.$request({
name: '',
description: '',
tags: '',
filter: '',
file: '',
response: '',
image_path: '',
}),
errorMessage: '',
successMessage: '',
submitted: false,
};
},
methods: {
onSubmit() {
const bodyFormData = new FormData();
bodyFormData.append('name', 'iamge1');
bodyFormData.append('description', 'An image');
bodyFormData.append('tags', 'Winter');
bodyFormData.append('filter', '1977');
bodyFormData.append('user_id', 2);
bodyFormData.append('file', this.file);
bodyFormData.append('image_path', '???');
this.onFileChange();
axios({
method: 'post',
url: 'http://localhost/bit703/module6/api/v1/images',
data: bodyFormData,
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((response) => {
this.resposne = response;
});
},
onFileChange(e) {
const image = e.target.files[0];
this.file = image;
},
},
};
</script>

Default content-type does not replace with new content-type (form-data) in axios in react native app for uploading image

I want to upload an image with axios in react native. This is my function which call upload image web service api:
function _uploadImgToServer(item) {
const file = {
uri: item.imgData.path,
type: item.imgData.mime,
name: 'ana' + item.imgId
}
const body = new FormData();
body.append('file', file);
console.log('uploadResult saga0', body)
dispatch(uploadImg({ body: JSON.stringify(body)}))
}
this is my axios config:
const instance = axios.create({
baseURL: '****',
responseType: 'json',
timeout: 10000,
headers: {
'WEB_TOKEN': '*****',
'UNIQUE_ID': '*****',
'UNIQUE_KEY': '*****',
Accept: "application/json",
'Content-Type': "multipart/form-data"
},
});
And I call my web service like bellow:
try {
const response = await instance.post(url, data);
return Promise.resolve(response.data);
} catch (error) {
return Promise.reject(error.response);
}
Part of the response I get in last part is:
'My log result' { data: { Code: 3, Message: 'Invalid Entry', Value: null },
status: 200,
statusText: undefined,
headers:
{
...
'content-type': 'application/json; charset=utf-8',
...
},
config:
{ url: 'upload',
method: 'post',
data: '{"_parts":[[{"uri":"file:///data/data/***packageName***/cache/react-native-image-crop-picker/IMG-20201222-WA0017.jpg","type":"image/jpeg","name":"ana_pu8kweg4e"},null]]}',
headers:
{ Accept: 'application/json',
'Content-Type': 'multipart/form-data',
WEB_TOKEN: '*****',
UNIQUE_ID: '****',
UNIQUE_KEY: '****' },
baseURL: '****',
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 10000,
adapter: [Function: xhrAdapter],
responseType: 'json',
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus] },
...
}
As you see in my log result, the content-type in header I have sent is 'multipart/form-data' but server has received 'application/json; charset=utf-8' so I cannot upload my image.
It is worth to mention that if I do not use JSON.stringify, content-type will not be sent at all. I have searched a lot but I could not find any useful response.
I found that my problem was not about "content-type" at all. I had to put image type at the end of the image name.
const file = {
uri: item.imgData.path,
type: item.imgData.mime,
name: 'ana'+item.imgId+'.jpeg'
}
I've just added '.jpeg' at the end of the name. I think it is depended on the backend programmer coding algorithm and It cannot cause problem always.

React Native video file upload

I am currently uploading videos and images using base64 encoding but it was highly recommended to use an alternative to this. I am using RNFetchBlob to read the encoded file and then attach it to SuperAgent for uploading. I have seen some examples of using FormData to attach the file but cannot find a complete working example. If someone could provide a code example on how to achieve this I would greatly appreciate it.
RNFetchBlob.fs.readFile(filePath, 'base64')
.then((base64data) => {
let base64Image = `data:video/mp4;base64,${base64data}`;
let uploadRequest = superagent.post(uploadURL)
uploadRequest.attach('file',base64Image)
Object.keys(params).forEach((key) => {
uploadRequest.field(key,params[key])
})
uploadRequest.on('progress', function(e) {
this.props.setVideoUploadProgress(e.percent)
}.bind(this))
uploadRequest.end((err,resp) => {
})
})
I am using react-native-image-picker to allow users to select or record a video, which gives me a URI of the video file path. Then I use RNFetchBlob to upload it to the server.
RNFetchBlob.fetch('POST', 'Upload API endpoint', {
...this.getHeader(),
'Content-Type': 'multipart/form-data'
// Change BASE64 encoded data to a file path with prefix `RNFetchBlob-file://`.
// Or simply wrap the file path with RNFetchBlob.wrap().
}, [
// element with property `filename` will be transformed into `file` in form data
{ name: 'file', filename: 'video.mp4', data: RNFetchBlob.wrap(this.state.videoUri) },
// custom content type
]).uploadProgress({ interval: 250 }, (written, total) => {
let uploaded = (written / total) * 100
this.setState({
uploadProgress: uploaded.toFixed(1)
})
})
.then((response) => {
if (response.ok) {
this.setState({
uploading: false,
uploadSuccess: true,
uploadFailed: false,
})
}
}).catch((err) => {
this.setState({
uploading: false,
uploadSuccess: false,
uploadFailed: true,
})
})
Basically you have to give the path of your image, audio or video to fetch blob. The following code worked for me:
RNFetchBlob.fetch(
'POST',
`${BASE_URL}vehicle/vehicleRegistration`,
{
Authorization: 'Bearer ' + authToken,
'Content-Type': 'multipart/form-data,octet-stream',
},
[
{
name: 'photo',
filename: 'vid.mp4',
data: RNFetchBlob.wrap(vehicleImage.uri),
},
{
name: 'email',
data: user.email,
},
{
name: 'userId',
data: user.id,
},
{
name: 'vehicleType',
data: values.vehicleType,
},
{
name: 'make',
data: values.make,
},
{
name: 'buildYear',
data: values.buildYear,
},
{
name: 'model',
data: values.model,
},
{
name: 'nickName',
data: values.nickName,
},
{
name: 'engineSize',
data: values.engineSize,
},
],
)
.uploadProgress((written, total) => {
console.log('uploaded', written / total);
})
.then(response => response.json())
.then(RetrivedData => {
console.log('---retrieved data------', RetrivedData);
Toast.show({
text1: 'Success',
text2: 'Vehicle Added to Garage!',
type: 'success',
});
})
.catch(err => {
console.log('----Error in adding a comment----', err);
Toast.show({
text1: 'Request Failed',
text2: err?.response?.data?.message,
type: 'error',
});
});

Proxy `changeOrigin` setting doesn't seem to work

I'm using Vue CLI 3.0.0 (rc.10) and am running two servers (backend server and WDS) side by side.
I followed the devServer.proxy instructions on the Vue CLI documentation to add a proxy option to my vue.config.js. I also followed the instructions for the http-proxy-middleware library to supplement the options:
module.exports = {
lintOnSave: true,
outputDir: '../priv/static/',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:4000',
changeOrigin: true,
ws: true,
},
},
},
};
My understanding is that the changeOrigin: true option needs to dynamically change the Origin header on the request to "http://localhost:4000". However, requests from my app are still being sent from http://localhost:8080 and they trigger CORS blockage:
Request URL: http://localhost:4000/api/form
Request Method: OPTIONS
Status Code: 404 Not Found
Remote Address: 127.0.0.1:4000
Host: localhost:4000
Origin: http://localhost:8080 <-- PROBLEM
What am I doing wrong?
I was having basically the same problem, and what finally worked for me was manually overwriting the Origin header, like this:
module.exports = {
lintOnSave: true,
outputDir: '../priv/static/',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:4000',
changeOrigin: true,
ws: true,
onProxyReq: function(request) {
request.setHeader("origin", "http://localhost:4000");
},
},
},
},
};
this is my vue.config.js, work fine for me:
module.exports = {
baseUrl: './',
assetsDir: 'static',
productionSourceMap: false,
configureWebpack: {
devServer: {
headers: { "Access-Control-Allow-Origin": "*" }
}
},
devServer: {
proxy: {
'/api': {
target: 'http://127.0.0.1:3333/api/',
changeOrigin: false,
secure: false,
pathRewrite: {
'^/api': ''
},
onProxyReq: function (request) {
request.setHeader("origin", "http://127.0.0.1:3333");
}
}
}
}
}
axios.config.js:
import axios from 'axios';
import { Message, Loading } from 'element-ui'
// axios.defaults.baseURL = "http://127.0.0.1:3333/";
axios.defaults.timeout = 5 * 1000
// axios.defaults.withCredentials = true
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
let loading = null;
function startLoading() {
loading = Loading.service({
lock: true,
text: 'loading....',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.8)'
})
}
function endLoading() {
loading.close()
}
axios.interceptors.request.use(
(confing) => {
startLoading()
// if (localStorage.eToken) {
// confing.headers.Authorization = localStorage.eToken
// }
return confing
},
(error) => {
console.log("request error: ", error)
return Promise.reject(error)
}
)
axios.interceptors.response.use(
(response) => {
endLoading()
return response.data;
},
(error) => {
console.log("response error: ", error);
endLoading()
return Promise.reject(error)
}
)
export const postRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
export const uploadFileRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
headers: {
'Content-Type': 'multipart/form-data'
}
});
}
export const getRequest = (url) => {
return axios({
method: 'get',
url: url
});
}
export const putRequest = (url, params) => {
return axios({
method: 'put',
url: url,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
export const deleteRequest = (url) => {
return axios({
method: 'delete',
url: url
});
}
api request:
import {postRequest} from "../http";
const category = {
store(params) {
return postRequest("/api/admin/category", params);
}
}
export default category;
the principle:
According to https://github.com/chimurai/http-proxy-middleware#http-proxy-options, a header option works for me.
devServer: {
proxy: {
'/api': {
target: 'http://127.0.0.1:3333/api/',
headers: {
origin: "http://127.0.0.1:3333"
}
}
}
}
changeOrigin only changes the host header!!!
see the documents http-proxy-middleware#http-proxy-options
option.changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL