I was always using plain JS und fetch call to handle API, they are working fine, now I want to replace all fetch with axios, so far the axios get calls are all working, but the axios post call are not, please guide:
the original fetch post from client side is like this, i need to send 3 values to server
const postTrip = async(location = '', daysToGo = '', notes ='') => {
const res = await fetch('http://localhost:7777/addData', {
method: 'POST',
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({location, daysToGo, notes}),
})
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response from server");
}
updateUI(daysToGo);
}
from server side
app.post('/addData', async (req, res) => {
try {
const city = req.body.location;
const dayLength = req.body.daysToGo;
const memo = req.body.notes;
let geo = await getGeo(city);
let weather = await getWeather(geo.lat, geo.lng, dayLength);
let image = await getImage(city);
const newEntry = {
geo,
weather,
image,
memo
}
projectData = newEntry;
res.status(201).send(projectData);
now I try to change client fetch post to axios post like this
const postTrip = async(location = '', daysToGo = '', notes ='') => {
const res = await axios('http://localhost:7777/addData', {
method: 'POST',
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({location, daysToGo, notes}),
})
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response from server");
}
updateUI(daysToGo);
}
and change the server side like this:
app.post('/addData', async (req, res) => {
try {
const city = req.data.location;
const dayLength = req.data.daysToGo;
const memo = req.data.notes;
let geo = await getGeo(city);
let weather = await getWeather(geo.lat, geo.lng, dayLength);
let image = await getImage(city);
const newEntry = {
geo,
weather,
image,
memo
}
projectData = newEntry;
res.status(201).send(projectData);
it dosen't work, the server didn't get the three values from front, where is wrong?
With axios you don't have to stringify the body.
const postTrip = async(location = '', daysToGo = '', notes ='') => {
const res = await axios('http://localhost:7777/addData', {
method: 'POST',
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json"
},
data: {location, daysToGo, notes},
})
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response from server");
}
updateUI(daysToGo);
}
Related
I'm trying to use HERE's RouteMatching API of JavaScript
Current full code is here: https://github.com/code4history/ShibeContour/blob/d7e56a7/here_mapmatcher.js
For authentication, I coded like this:
import properties from "properties"
import hmacSHA256 from 'crypto-js/hmac-sha256.js'
import Base64 from 'crypto-js/enc-base64.js'
import fetch from 'node-fetch'
import {promises as fs} from "node:fs"
const getProps = async () => {
return new Promise((res) => {
properties.parse("./credentials.properties", {path: true}, function (error, data) {
res(data)
})
})
}
const getToken = async (props) => {
const nonce = `${performance.now()}`
const timestamp = Math.floor((new Date()).getTime() / 1000)
const parameters = [
"grant_type=client_credentials",
`oauth_consumer_key=${props["here.access.key.id"]}`,
`oauth_nonce=${nonce}`,
"oauth_signature_method=HMAC-SHA256",
`oauth_timestamp=${timestamp}`,
"oauth_version=1.0"
].join("&")
const encoding_params = encodeURIComponent(parameters)
const base_string = `POST&${encodeURIComponent(props["here.token.endpoint.url"])}&${encoding_params}`
console.log(base_string)
const signing_key = `${props["here.access.key.secret"]}&`
const hmac_digest = encodeURIComponent(Base64.stringify(hmacSHA256(base_string, signing_key)))
const headers = {
"Authorization": `OAuth oauth_consumer_key="${props["here.access.key.id"]}",oauth_nonce="${nonce}",oauth_signature="${hmac_digest}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="${timestamp}",oauth_version="1.0"`,
"Cache-Control": "no-cache",
"Content-Type": "application/x-www-form-urlencoded"
}
const body = `grant_type=client_credentials`
const response = await fetch(props["here.token.endpoint.url"], {
method: 'post',
body,
headers
})
return response.json()
}
This works well, I got authentication token successfully.
Like this:
{
access_token: 'eyJhbGciOiJSUzUxMiIsImN0eSI6IkpXVCIsImlzcyI6IkhFUkUiLCJhaWQiOiJIZ0NSaFV4...',
token_type: 'bearer',
expires_in: 86399,
scope: 'hrn:here:authorization::org...'
}
But even I used this access_token, route matching call causes authentication error.
Code is:
const main = async () => {
const props = await getProps()
const token_data = await getToken(props)
const body = await fs.readFile("gps/8DD83AC3-8B5A-4108-9CC0-2B78CF9936EC.kml", {encoding: "UTF-8"})
const headers = {
"Authorization": `Bearer ${token_data.access_token}`,
"Cache-Control": "no-cache",
"Content-Type": "application/octet-stream"
}
const response = await fetch(`https://routematching.hereapi.com/v8/calculateroute.json?routeMatch=1&mode=fastest;car;traffic:disabled&apiKey=${props["here.access.key.id"]}`, {
method: 'post',
body,
headers
})
const respond = await response.json()
console.log(respond)
}
main()
Error response was like this:
{
error: 'Forbidden',
error_description: 'These credentials do not authorize access'
}
What is wrong?
I can't imagine what is wrong.
Finally I found the reason
API URL is not match.
We can find many candidate urls,
https://fleet.api.here.com/2/calculateroute.json
https://routematching.hereapi.com/v8/calculateroute.json
etc...
but true working url is only
https://routematching.hereapi.com/v8/match/routelinks
which we can find in this document.
https://platform.here.com/services/details/hrn:here:service::olp-here:route-matching-8/api-ref
Once I changed API endpoint to this correct one, it works well.
This issue only occurs with posts with multipart video, Posts with images and videos below 4MB are working, when posting to Posts API i get a response with Status OK and the post URN in the header but when i try getting the post data using the given URN i'm getting error 404.
Here is the function that i am using to upload the video to LinkedIn.
const uploadVideo = async (linkedinId, accessToken, videoUrl) => {
/* Fetching video from Google storage */
const videoData = await axios.get(videoUrl, { responseType: 'arraybuffer' });
const contentType = videoData.headers['content-type'];
const videoSize = videoData.headers['content-length'];
const url = 'https://api.linkedin.com/rest/videos';
const body = {
initializeUploadRequest: {
owner: `urn:li:organization:${linkedinId}`,
fileSizeBytes: Number(videoSize),
},
};
const headers = {
Authorization: `Bearer ${accessToken}`,
'X-Restli-Protocol-Version': '2.0.0',
'x-li-format': 'json',
'LinkedIn-Version': 202207,
};
const response = await axios.post(url, body, { headers, params: { action: 'initializeUpload' } });
const { uploadInstructions } = response.data.value;
const asset = response.data.value.video;
/* Uploading video */
try {
const uploadPromises = uploadInstructions.map(async ({ uploadUrl, firstByte, lastByte }) => {
const arrayBuffer = videoData.data.slice(firstByte, lastByte);
return axios({
url: uploadUrl,
method: 'POST',
data: arrayBuffer,
headers: {
'Content-Type': contentType,
},
maxBodyLength: Infinity,
maxContentLength: Infinity,
});
});
const uploadResponses = await Promise.all(uploadPromises);
const finalizeUploadBody = {
finalizeUploadRequest: {
video: asset,
uploadToken: '',
uploadedPartIds: uploadResponses.map((uploadResponse) => uploadResponse.headers.etag),
},
};
await axios.post(url, finalizeUploadBody, {
headers: {
...headers,
'Content-Type': 'application/json',
},
params: {
action: 'finalizeUpload',
},
});
} catch (error) {
throw error;
}
return asset;
};
Here is the function that i am using to publish the post to LinkedIn.
const publishContent = async (
linkedinId,
accessToken,
media,
) => {
const url = 'https://api.linkedin.com/rest/posts';
const body = {
author: `urn:li:organization:${linkedinId}`,
commentary: 'content',
visibility: 'PUBLIC',
lifecycleState: 'PUBLISHED',
distribution: {
feedDistribution: 'MAIN_FEED',
},
};
const asset = await uploadVideo(linkedinId, accessToken, media.urls[0], isPage);
body.content = {
media: {
title: 'Title',
id: asset,
},
};
const headers = {
Authorization: 'Bearer ' + accessToken,
'X-Restli-Protocol-Version': '2.0.0',
'x-li-format': 'json',
'LinkedIn-Version': 202207,
};
return axios.post(url, body, { headers });
};
I am building a comments section onto a Node/Express app for family reunions. I first wrote it all on the server side, but then ran into the issue where I was unable to update the DOM after posting the comment without refreshing the page.
My research yielded that I could use AJAX or the fetch API to do this, client-side.
I'm using some client-side JavaScript to post comments. I have a route for the POST request:
router.post('/:reunionId', isAuth, reunionController.postComment);
The controller code is:
exports.postComment = (req, res, next) => {
const commentText = req.body.newComment;
const reunionId = req.body.reunionId;
const foundReunion = Reunion.findById(reunionId)
.populate({
path: 'comments',
options: { sort: { createdAt: -1 } },
})
.then((reunion) => {
console.log(reunion);
const comment = new Comment({
_id: new mongoose.Types.ObjectId(),
text: commentText,
reunionId: new mongoose.Types.ObjectId(reunionId),
userId: req.user._id,
});
foundReunion.comments.push(comment);
comment.save();
foundReunion.save();
console.log('Operation completed successfully');
return foundReunion;
})
.catch((error) => {
const newError = new Error(error);
newError.httpStatusCode = 500;
return next(newError);
});
};
And the client-side code:
const commentForm = document.getElementById('comment-form');
const commentInput = document.getElementById('newComment');
const commentsContainer = document.getElementById('allComments');
let commentText = document.getElementById('newComment').value;
const reunionId = document.getElementById('reunionId').value;
const csrfToken = document.getElementById('csrf').value;
commentForm.addEventListener('submit', handleCommentSubmit, false);
commentInput.addEventListener('change', (event) => {
commentText = event.target.value;
});
async function handleCommentSubmit(event) {
event.preventDefault();
console.log('Someone clicked the comment submit button...');
console.log(csrfToken); // This works.
console.log(reunionId); // This works.
console.log(commentText); // This works.
const url = `http://localhost:3006/reunions/${reunionId}`;
fetch(url, {
method: 'POST',
credentials: 'include',
headers: {
'X-CSRF-Token': csrfToken,
},
body: { // This is not working.
reunionId,
commentText,
},
})
.then((response) => {
const d = response.comment.createdAt.getDate();
const m = monthNames[response.comment.createdAt.getMonth()];
const y = response.comment.createdAt.getFullYear();
const commentDiv = document.createElement('div');
commentDiv.classList.add('comments-container');
const commentP = doucment.createElement('p');
commentP.classList.add('comment-header-text');
const email = response.comment.userId.email;
const hr = document.createElement('hr');
commentP.textContent = `On ${m}+ ' ' +${d}+ ', ' +${y}, ${email} wrote:`;
commentDiv.appendChild(commentP);
commentDiv.appendChild(commentText);
commentDiv.appendChild(hr);
commentsContainer.appendChild(commentDiv);
})
.catch((error) => console.log(error));
The client makes the POST request, properly passes the csrf token, but the server cannot read the reunionId or commentText from the body of the request. I get Reunion.findOne({ null }) in the server logs.
I am simply not sure what Content-Type to declare, whether I need to at all, or how to pass the two pieces of data I need in the body of the call to fetch.
Thanks very much in advance.
The body of a post must always be a string. What you are missing is you need to JSON.strigify your object and them make add the content-type header to specify that the body is application/json:
fetch(url, {
method: 'POST',
credentials: 'include',
headers: {
'X-CSRF-Token': csrfToken,
'Content-Type': 'application/json'
},
body: JSON.stringify({
reunionId,
commentText,
}),
})
I'm trying to develop a web page that get the data from another web application using axios.get and I wanna insert this data into the Postgres database, the problem is data is inside the then promise, I can not access it to insert it to the database, how can I do that or how can I access the data outside the then
I wanna insert var rn0 ty0
this is the main.js
const axios = require('axios')
const InsertToDataBase = require("./InsertToDataBase");
const username = 'admin'
const password = 'admin'
const token = Buffer.from(`${username}:${password}`, 'utf8').toString('base64')
const urlLAMP_0 = 'http://127.0.0.1:8282/~/mn-cse/mn-name/LAMP_0/DATA/la'
const urlLAMP_1 = 'http://localhost:8282/~/mn-cse/mn-name/LAMP_1/DATA/la'
function getDataLAMP_0(){
axios.get(urlLAMP_0, {
headers: {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin':'*',
"X-M2M-RI":"OM2M-webpage",
'Authorization': `Basic ${token}`,
'Accept': 'application/json',
'mode': 'cors',
'credentials': 'include',
}
})
.then(function(response) {
document.getElementById("rn0").textContent = response.data['m2m:cin'].rn;
var rn0 = response.data['m2m:cin'].rn;
document.getElementById("ty0").textContent = response.data['m2m:cin'].ty;
var ty0 = response.data['m2m:cin'].ty;
document.getElementById("ri0").textContent = response.data['m2m:cin'].ri;
document.getElementById("pi0").textContent = response.data['m2m:cin'].pi;
document.getElementById("ct0").textContent = response.data['m2m:cin'].ct;
document.getElementById("lt0").textContent = response.data['m2m:cin'].lt;
document.getElementById("st0").textContent = response.data['m2m:cin'].st;
document.getElementById("cnf0").textContent = response.data['m2m:cin'].cnf;
document.getElementById("cs0").textContent = response.data['m2m:cin'].cs;
document.getElementById("con0").textContent = response.data['m2m:cin'].con;
})
}
getDataLAMP_0();
InsertToDataBase.insertdatatolamp0(rn0,ty0);
this is the InsertToDataBase.js
const {Client} = require('pg')
const client = new Client({
user:"postgres",
password:"admin",
host:"localhost",
port:"5432",
database:"postgres",
})
function insertdatatolamp0(rn0,ty0){
client.connect()
.then(()=>console.log("connected successfuly"))
.then(()=>client.query("insert into lamp0 values ($1,$2)",[rn0,ty0]))
.catch(e=> console.log(e))
.finally(()=> client.end())
}
module.exports = { insertdatatolamp0 };
You can chain promises. This will give you enough flexibility to do a series of actions one after the other, in your case change textContent and then insert some values into the database.
const axios = require("axios");
const InsertToDataBase = require("./InsertToDataBase");
const username = "admin";
const password = "admin";
const token = Buffer.from(`${username}:${password}`, "utf8").toString("base64");
const urlLAMP_0 = "http://127.0.0.1:8282/~/mn-cse/mn-name/LAMP_0/DATA/la";
const urlLAMP_1 = "http://localhost:8282/~/mn-cse/mn-name/LAMP_1/DATA/la";
function getDataLAMP_0() {
axios
.get(urlLAMP_0, {
headers: {
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Origin": "*",
"X-M2M-RI": "OM2M-webpage",
Authorization: `Basic ${token}`,
Accept: "application/json",
mode: "cors",
credentials: "include",
},
})
.then(function (response) {
document.getElementById("rn0").textContent = response.data["m2m:cin"].rn;
document.getElementById("ty0").textContent = response.data["m2m:cin"].ty;
document.getElementById("ri0").textContent = response.data["m2m:cin"].ri;
document.getElementById("pi0").textContent = response.data["m2m:cin"].pi;
document.getElementById("ct0").textContent = response.data["m2m:cin"].ct;
document.getElementById("lt0").textContent = response.data["m2m:cin"].lt;
document.getElementById("st0").textContent = response.data["m2m:cin"].st;
document.getElementById("cnf0").textContent =
response.data["m2m:cin"].cnf;
document.getElementById("cs0").textContent = response.data["m2m:cin"].cs;
document.getElementById("con0").textContent =
response.data["m2m:cin"].con;
return response;
})
.then((response) => {
var rn0 = response.data["m2m:cin"].rn;
var ty0 = response.data["m2m:cin"].ty;
InsertToDataBase.insertdatatolamp0(rn0,ty0);
});
}
getDataLAMP_0();
You can do this with the help of Promise, here is a simple example
async function httpGetDataHandler() {
const url = "https://jsonplaceholder.typicode.com/posts";
const response = await fetch(url);
const parsedJson = await response.json();
const data = await parsedJson;
return Promise.resolve(data);
}
const getDataLAMP_0 = () => {
httpGetDataHandler()
.then((data) => {
// do your document.getElementById stuff in here
// I'm just returning the first index value, you can do whatever you want like return rn0
return data[0]
})
.then((data) => {
console.log("insert to database: ", data);
});
};
getDataLAMP_0();
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);
}