I'm using Reactjs saga to send a post request using fetch. Also I'm trying to use formidable instead of usual body-parser. I'm getting weird parsing issues. What am I doing wrong?
// saga simplified piece of code
const { loginEmail, loginPwd } = request.payload;
let postLoginSubmitOptions = {
method: "POST",
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type' : 'application/x-www-form-urlencoded'
},
body: JSON.stringify({
loginEmail: loginEmail,
loginPwd: loginPwd
})
};
const response = yield call(fetch, `http://www.example.com/register`, postLoginSubmitOptions);
// expressjs side, simplified view
router.post('/register', function(req, res, next) {
console.log('registering user');
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
if(err){
console.log(err);
}
console.log(`incoming fields via form parse`);
console.log(fields); // { '{"loginEmail":"my-email#gmail.com","loginPwd":"my-password"}': '' }
console.log(fields.loginEmail); // undefined
});
}
pass content type as json
let postLoginSubmitOptions = {
method: "POST",
headers: new Headers({'content-type': 'application/json'}),
body: JSON.stringify({
loginEmail: loginEmail,
loginPwd: loginPwd
})
};
I don't know where exactly the problem was but tried encoding data differently and then it worked. Getting a nice parsed object now with formidable: { loginEmail: 'dan#dan.com', loginPwd: 'asjdfkjsadlf' }
function sendData(data) {
const { loginEmail, loginPwd } = request.payload;
const body = { loginEmail, loginPwd };
var urlEncodedData = "";
var urlEncodedDataPairs = [];
var name;
for(name in body) {
urlEncodedDataPairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(body[name]));
}
urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+');
var httpHeaders = {
'Content-Type' : 'application/x-www-form-urlencoded',
'Accept' : 'application/json'
}
let postOptions = {
method: 'post',
headers: new Headers(httpHeaders),
/*mode: 'no-cors',*/
body: urlEncodedData
};
try {
const response = yield call(fetch, `http://www.example.com/register`, postOptions);
const data = yield call([response, response.json]);
console.log(`data returned by fetch`);
console.log(data);
yield put({type: 'LOGIN_SUBMIT_RESPONSE', payload: data.message})
} catch (e) {
console.log(`error fetch post object`);
}
}
Thanks everyone!
Related
TDLR: Using s3 presigned post url to upload file to s3. Works fine on the browser but fails on the server.
I have a simple lambda function that generates presigned post url that can be consumed either in the browser or in the server.
During testing I noticed that the upload works fine one the browser but fails if I try to upload a file from a server even tho the code is identical.
The error i get is:
You must provide the Content-Length HTTP header
Detailed error:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>MissingContentLength</Code>
<Message>You must provide the Content-Length HTTP header.</Message>
<RequestId>JP75YMFARK0G3X5Z</RequestId>
<HostId>toHsKmxmVYYAtac94cQoy8wXoregKG3PNBm97c3gQewEmKxLggcumTAP882T/pJNWx/lxRgH98A=</HostId>
</Error>
Request failed with status code 411
I checked online and found many threads about this issue but unfortunately not a single suggestion helped me.
Code I am running in the server
const axios = require('axios');
const { createReadStream, readFileSync } = require('fs');
const FormData = require('form-data');
const getPostPresignedUrl = async () => {
var config = {
method: 'post',
url: LAMBDA_GET_URL,
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
key: 'test-2.jpg',
fileType: 'image/jpeg',
}),
};
const {
data: { data },
} = await axios(config);
return data;
};
const uploadFileToS3 = async (fields, url) => {
const formData = new FormData();
Object.entries(fields).map(([key, value]) => {
formData.append(key, value);
});
const file = createReadStream('./test-1.jpg');
formData.append('file', file);
try {
const { data } = await axios({
url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
});
} catch (error) {
if (error instanceof axios.AxiosError) {
console.log(error.response.data);
}
console.log(error.message);
}
};
const init = async () => {
const { fields, url } = await getPostPresignedUrl();
await uploadFileToS3(fields, url);
};
init();
Code I am running in the browser:
const form = document.getElementById('form');
const input = document.getElementById('file');
const getPostPresignedUrl = async (name) => {
var config = {
method: 'post',
url: LAMBDA_GET_URL,
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
key: name,
fileType: 'image/jpeg',
}),
};
const {
data: { data },
} = await axios(config);
return data;
};
const uploadFileToS3 = async (fields, url, file) => {
const formData = new FormData();
Object.entries(fields).map(([key, value]) => {
formData.append(key, value);
});
formData.append('file', file);
try {
const { data } = await axios({
url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
});
} catch (error) {
if (error instanceof axios.AxiosError) {
console.log(error.response.data);
}
console.log(error.message);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
const file = input.files[0];
const data = await getPostPresignedUrl(file.name);
await uploadFileToS3(data.fields, data.url, file);
};
form.onsubmit = handleSubmit;
Can someone take a look at the code below.
I try to make a converter work, which makes a png from a jpg.
I keep getting this error:
{"message":"Please provide an API key or token."}
This is the code:
const {
file,
filename,
mimetype,
token,
size,
folderid,
} = inputs;
var myHeaders = new Headers();
myHeaders.append("x-oc-api-key", "API KEY");
myHeaders.append("Content-Type", "application/json");
var raw = {
type: 'remote',
source: file}
conversion: {
target: 'png'}
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
const {url} = inputs;
try {
const response = await fetch("www.apiwebsite.com/jobs", requestOptions);
const outputvariableurl = await response.json();
return { outputvariableurl }
} catch (err) {
const error = {
code: 'unknownError',
message: 'Something went wrong.',
rawError: err,
}
return [1, { error }]
}
I'm new to JavaScript and Promises. I need to send an array of requests using Promise.all and await. Unfortunately, I do not know the size of the array, so it needs to be dynamic. The array would be requests. Ex:
let arrayOfApiCreateRecords = [];
arrayOfApiCreateRecords.push(apiCreateRecords(req, { clientHeaders: headers, record }));
let responses = await Promise.all( arrayOfApiCreateRecords );
I tried to write my code like this, but I seem to be stuck. Is it possible to rewrite the code using Promise.all and await with a dynamic array of requests? Please advise. Below is what I have:
'use strict';
const { apiCreateRecords } = require('../../../records/createRecords');
const createRecords = async (req, headers) => {
let body = [];
let status;
for(let i = 0; i < req.body.length; i++) {
let r = req.body[i];
let record = {
recordId: r.record_Id,
recordStatus: r.record_status,
};
const response = await apiCreateRecords(req, { clientHeaders: headers, record });
status = (status != undefined || status >= 300) ? status : response.status;
body.push(response.body);
};
return { status, body };
};
module.exports = {
createRecords,
};
Okay, I'm going to use fetch API to demonstrate the usage of Promise.all()
Normal usage (for one fetch call)
let user = { username: 'john.doe', password: 'secret' };
try{
let res = await fetch('https://example.com/user/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
console.log('User creation response: ', res);
}
catch(err){
console.error('User creation error: ', err);
}
Now let's use Promise.all()
const users = [
{ username: 'john.doe', password: 'secret' },
{ username: 'jane.doe', password: 'i-love-my-secret' }
];
const requests = [];
// push first request into array
requests.push(
fetch('https://example.com/user/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user[0])
})
);
// push second request into array
requests.push(
fetch('https://example.com/user/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user[1])
})
);
try{
const responses = await Promise.all(requests);
console.log('User creation responses: ', responses);
}
catch(err){
console.log('User creation error: ', err);
}
I've got an API where some of the parameters need to be given within the URL.
Example of how my api url looks like: https://www.server.com/api/actions/execute?auth_type=apikey&data={"Name": "name","Email" : "email"}
What my code looks like right now
register = async () => {
let data = {"Name":this.state.name, "Email":this.state.email}
data = JSON.stringify(data)
let URL = 'https://www.server.com/api/actions/execute?auth_type=apikey&data=';
fetch(URL, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json'
}),
body: data
})
.then((response) => response.text())
.then((responseText) => {
alert(responseText);
})
.catch((error) => {
console.error(error);
});
}
The response I get on my device:
{"code":"succes","details":{"userMessage":["java.lang.Object#2e56000c"],"output_type":void","id:"20620000000018001"},"message":"function executed succesfully"}
This is alle working fine when I test it in postman but I can't get it to work within React-Native. I've tried stuff like 'Content-Type':'application/x-www-form-urlencoded' already.
First install the package axios from the url https://www.npmjs.com/package/react-native-axios
Then create two service for handling get and post request so that you can reuse them
GetService.js
import axios from 'axios';
let constant = {
baseurl:'https://www.sampleurl.com/'
};
let config = {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
}
};
export const GetService = (data,Path,jwtKey) => {
if(jwtKey != ''){
axios.defaults.headers.common['Authorization'] = 'Bearer '+jwtKey;
}
try{
return axios.get(
constant.baseUrl+'api/'+Path,
data,
config
);
}catch(error){
console.warn(error);
}
}
PostService.js
import axios from 'axios';
let constant = {
baseurl:'https://www.sampleurl.com/'
};
let config = {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
}
};
export const PostService = (data,Path,jwtKey) => {
if(jwtKey != ''){
axios.defaults.headers.common['Authorization'] = 'Bearer '+jwtKey;
}
try{
return axios.post(
constant.baseUrl+'api/'+Path,
data,
config
);
}catch(error){
console.warn(error);
}
}
Sample code for using get and post services is given below
import { PostService } from './PostService';
import { GetService } from './GetService';
let uploadData = new FormData();
uploadData.append('key1', this.state.value1);
uploadData.append('key2', this.state.value2);
//uploadData.append('uploads', { type: data.mime, uri: data.path, name: "samples" });
let jwtKey = ''; // Authentication key can be added here
PostService(uploadData, 'postUser.php', jwtKey).then((resp) => {
this.setState({ uploading: false });
// resp.data will contain json data from server
}).catch(err => {
// handle error here
});
GetService({}, 'getUser.php?uid='+uid, jwtKey).then((resp) => {
// resp.data will contain json data from server
}).catch(err => {
// handle error here
});
If you need to pass parameters via URL you should use GET, if you use POST then the parameters should be passed in the body
When a GET(https://graph.microsoft.com/v1.0/users/ {{user_id}} /photo/$value) request is made, the response data will be written with the same characters as image
.
After converting to base64, I tried blob format but the picture does not appear.
router.js
router.get('/photo/:id',function (req,res) {
auth.getAccessToken().then(function (token){
let userId = req.params.id;
graph.getUserPhotoData(token, userId).then(function (result) {
res.json(result);
}).catch(function (e) { console.log(e) })
});
});
graph.js
function getUserPhoto(token, userId){
return axios({
method : 'get',
url : 'https://graph.microsoft.com/v1.0/users/'+{{user_id}}+'/photo/$value',
headers: {
'Authorization':token,
// 'Content-Type': 'image/jpeg',
},
responseType : 'blob'
})
}
async function getUserPhotoData(token,userId) {
try{
let userPhoto = getUserPhoto(token,userId);
let p = userPhoto.data;
// let photo = new Buffer(userPhoto.data).toString('base64');
return p; //...013O✿\u0011�e����|��>�4+�y��\u0017�"Y...
}catch (e) { console.log(e);}
}
index.js
$.get('/photo/'+userId, function(response) {
let binaryData = [];
binaryData.push(response);
const blobUrl = window.URL.createObjectURL(new Blob(binaryData, {type: "image/jpeg"}));
document.getElementById('user-img').setAttribute("src", blobUrl );
});
UPDATE: new Buffer is deprected. Please use
<img src={'data:image/jpeg;base64,' + Buffer.from(response.data, 'binary').toString('base64')}
Original answer
it works for me
const graphEndpoint = "https://graph.microsoft.com/v1.0/me/photo/$value";
const response = await axios(graphEndpoint, { headers: { Authorization: `Bearer ${token}` }, responseType: 'arraybuffer' });
const avatar = new Buffer(response.data, 'binary').toString('base64');
Finally found a solution to this! The previous answers didn't quite work for me. What I found that worked was:
const { data: photoValue} = await axios.request({
method: 'GET',
{ headers: { Authorization: `Bearer ${token}` },
responseType: 'blob',
url: 'https://graph.microsoft.com/v1.0/me/photo/$value',
});
const blobUrl = window.URL.createObjectURL(photoValue);
and then displaying it with <img src={blobUrl} />. This is the shortest answer in my opinion, and relies on the responseType: 'blob' being given.
I solved this problem.
router.js
const request = require('request');
router.get('/photo/:id',function (req,res) {
auth.getAccessToken().then(function (token){
let userId = req.params.id;
// graph.getUserPhotoData(token, userId).then(function (result) {
// console.log(result);
// res.json(result);
// }).catch(function (e) { console.log(e) })
request({ uri: 'https://graph.microsoft.com/beta/users/'+userId+'/photo/$value', method: "GET", headers:{'Authorization' : 'Bearer' + token}, encoding: null},
function(error, response, body) {
let data = "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
res.send(data); //data:image/jpeg;base64,/9j/4AAQSkZJRg...
});
});
});
index.js
$.get('/photo/'+ userId, function(response) {
document.getElementById('user-img').setAttribute("src", response);
});
'graph.js' is not needed.
reference :
Node.js get image from web and encode with base64