Using JavaScript Fetch with Formidablejs, Expressjs - javascript

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

Upload file to s3 using presigned post url in the server

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;

Javascript error saying that I do not provide an API token

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 }]
}

Promise.all() with dynamically sized array of requests using await

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);
}

Post action API with object parameter within the URL

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

How to get user's photo(profile) using Microsoft Graph API?

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

Categories

Resources