Using one function to handle both POST/GET API calls with axios - javascript

As the title says what I was trying to do is make a universal function to both do GET and POST calls with one function. However, because when sending a GET call it requires the params entry to contain the data, when sending data via POST it requires the data entry (if I'm not mistaken).
I currently have the following function;
function api(method, call, params){
return new Promise(function(resolve, reject){
axios({
url: call,
method,
params
}).then(function(response) {
var body = response.data;
if(body.status !== 1){
return reject(body.message);
}
resolve(body.response);
}).catch(function(err){
reject(err);
});
});
GET calls work fine as there is the params entry, but for POST calls it stops working. How can I fix this so I have one function to handle both calls?

Another way would be to accept config object as a parameter. Also, you do not need to wrap axios() in a new promiseasaxios()` returns a promise itsef.
function api(config) {
const baseUrl = "http://foo.baz";
const updatedConfig = Object.assign({}, config, {
// If you want to append base url to all api methods.
url: `${baseUrl}${config.url}`
});
return axios(updatedConfig).then(response => {
const body = response.data;
if (body.status !== 1) {
throw new Error(body.message);
}
return body.response;
});
}
Usage:
api({
url: "/user",
method: "get",
params: { id: "xyz" }
}).then(() => { });
or
api({
url: "/tag",
method: "post",
data: { tag: "abc" }
}).then(() => { });

I solved it by just pulling the object into a variable and adding the entry.
Example:
var data = {
url: call,
method
}
if(method.toLowerCase() === 'post'){
data['data'] = params;
}else{
data['params'] = params;
}
axios(data).then(function(response) ...

Related

ajax promise gets overidden

first i call getLiveData which gets data from the server
then some parts of ui are rendered and these parts calls bindLiveData with Id
sometimes data comes later then some parts of UI thats why i wait till request is done.
The problem gots tricky when there is an exception, since the method is called itself again (in realilty up to couple of times)
I will not have calls from UI again , since they call bindLiveData once after render
so In fail method i could grab all Ids and on next successfull ajax reqest i could assinged data.
But what happens then with my infoDataPromise ?? since it will be overidden on error
Does all 'fails' of the previous reqest will fire ? How to avoid this promise gets overriden?
var infoDataPromise;
var mydata;
function getLiveData() {
infoDataPromise = $.ajax({
type: "POST",
dataType: 'JSON',
contentType: 'application/json',
url: "someUrl",
success: function (data) {mydata = data; },
error: function () {
getLiveData();
}
});
}
function bindLiveData(Id) {
infoDataPromise.done(() => {
if (mydata) {
var item = mydata.find(x => x.Id === Id);
adjustUIForId(item);
}
}).fail(() => {
mydata = null;
});
}
Don't write functions that manipulate globals.
Return promises from functions instead
Use async/await syntax to make promises easier to manage
Use recursion to handle your retry attempts
const getLiveData = async () => {
const config = {
type: "POST",
dataType: 'JSON',
contentType: 'application/json',
url: "someUrl"
};
try {
return await $.ajax(config);
} catch (e) {
console.log(e);
return getLiveData();
}
}
const handleData = async () => {
const data = await getLiveData();
if (!data) return;
const item = data.find(x => x.Id === Id);
adjustUIForId(item);
};
handleData();
Now getLiveData returns a single promise that resolves when there is a successful request and you don't need to worry about any other promises. There's no overwriting going on.

How do I return the response from a cy.request through a function

I am trying to pass the result of an API request using the following function:
Add(someName)
{
cy.request ({
method: 'POST',
url: someURL,
body: {
name: someName
}
}).then(function(response){
return response
})
}
When I try to call this function however, it does not give me the content of the response (it gives me Undefined). I thought this probably has something to do with either asynchronosity (if that is a word),or the scope of the object and therefore tried aliasing the response or defining an object outside of the function (then assigning the response to that object), without any luck.
You just need a return on the cy.request() call.
Add(someName) {
return cy.request ({...})
.then(function(response) {
return response.body // maps the response to it's body
}) // so return value of function is response.body
}
The return value type is a Chainer (the same type as all Cypress commands) so you must use a .then() on it
myPO.Add('myName').then(body => ...
You don't need .then() after cy.request()
If you want the full response,
Add(someName) {
return cy.request ({...}) // don't need a .then() after this
// to return full response
}
How to await the result
If you want to await the result, use a Cypress.Promise as shown here
Add(someName) {
return new Cypress.Promise((resolve, reject) => {
cy.request ({...})
.then(response => resolve(response))
})
}
Awaiting
const response = await myPO.Add('myName')
You should try returning something in your function:
Add(someName)
{
return cy.request ({
method: 'POST',
url: someURL,
body: {
name: someName
}
}).then(function(response){
return response
})
}
And then get the value returned:
Add('val').then((data) => {console.log(data)})
This can be done using cy.wrap!
In the below example you can do anything before the return:
export const add = (someName) => {
cy.request({
method: 'POST',
url: someURL,
body: {
name: someName
}
}).then((resp) => {
cy.wrap(resp)
.as('requestResp')
})
// Here you can do anything
return cy.get('#requestResp')
}
Let's try the following:
Return the response from this function,
function getApiResponse(): Cypress.ObjectLike {
return cy.request ({
method: 'POST',
url: someURL,
body: {
name: someName
}
})
}
And then call it in the required places:
getApiResponse().then(response => {
cy.log(response);
});

Cloudflare Workers FETCH POST Type Error Failed to execute function

Multiple people have brought up issues similar to mine in this community and cloudflare's community. It still seems largely unsolved so I’m asking in hopes of a solution.
I’m trying to create a feature for users to sign up through mailchimp. User info goes from browser to workers to mail chimp. I’m getting the following errors:
TypeError: Failed to execute function: parameter 1 is not of type
‘Response’. at line 0, col -2
Request.Body is not being read
Request from Client:
const response = await axios({
method: "post",
url: "http://127.0.0.1:8787/signup",
data: {
MERGE0: email,
MERGE1: firstName,
MERGE2: lastName,
},
headers: {
"Content-Type": "application/json",
}
});
Workers part 1 (function to read request body):
https://developers.cloudflare.com/workers/examples/read-post
async function readRequestBody(request) {
const { headers } = request
const contentType = headers.get('content-type') || ''
if (contentType.includes('application/json')) {
return JSON.stringify(await request.json())
} else if (contentType.includes('application/text')) {
return request.text()
} else if (contentType.includes('text/html')) {
return request.text()
} else if (contentType.includes('form')) {
const formData = await request.formData()
const body = {}
for (const entry of formData.entries()) {
body[entry[0]] = entry[1]
}
return JSON.stringify(body)
} else {
// Perhaps some other type of data was submitted in the form
// like an image, or some other binary data.
return 'a file'
}
}
Workers part 2 (to Post JSON File to Mail Chimp):
https://developers.cloudflare.com/workers/examples/post-json
async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type') || ''
if (contentType.includes('application/json')) {
return JSON.stringify(await response.json())
} else if (contentType.includes('application/text')) {
return response.text()
} else if (contentType.includes('text/html')) {
return response.text()
} else {
return response.text()
}
}
Workers Part 3 (to Handle Post Request):
async function eventHandler(request) {
const pathname = request.url
try {
if (pathname.indexOf('signup') !== -1) {
const reqBody = await readRequestBody(request)
const { MERGE0, MERGE1, MERGE2 } = reqBody
// Construct req data
const data = {
members: [
{
email_address: MERGE0,
status: 'subscribed',
merge_fields: {
FNAME: MERGE1,
LNAME: MERGE2,
},
},
],
}
const postData = JSON.stringify(data)
const options = {
method: 'POST',
headers: {
Authorization: `auth ${MAILCHIMP_API_KEY}`,
},
body: postData,
}
const url = `https://us5.api.mailchimp.com/3.0/lists/${MAILCHIMP_AUDIENCE_ID}`
const res = await fetch(url, options)
const results = await gatherResponse(res)
return results
}
} catch (err) {
console.log(err)
}
}
addEventListener('fetch', event => {
event.respondWith(eventHandler(event.request))
})
A few other posts I’ve referenced:
https://community.cloudflare.com/t/fetch-with-post-method-ignores-body/147758/3
https://community.cloudflare.com/t/how-to-post-with-a-body-as-readable-stream/211335
https://community.cloudflare.com/t/using-get-fetch-for-api-javascript-worker/98297
You have this code:
event.respondWith(eventHandler(event.request))
The event.respondWith() function needs to take a Response object as its parameter. However, your eventHandler() function does not return a Response. In some cases, the function does not return a result at all, and in other cases, it returns a string.
In cases where you don't want to modify the request/response, you can have eventHandler pass through the request to origin like so:
return fetch(request);
In cases where you have received a response from the origin, and you want to return it directly to the client unmodified, you should just return repsonse instead of return response.text().
In cases where you have created some new response text that you want to return, you need to wrap it in a Response, like:
return new Respnose(text, {headers: {"Content-Type": "text/plain"}});

Need to call Two APIs In Loop using node js

I have an array of ssn number and I have two api list in which I need to pass ssn number as request json so I need to call both api inside ssn loop so I pass ssn to json request during call both api but code is not work properly both api call at a time simulteniously, Where I need to call both api one by one.
Both API details and code are as follow
My Code:
let ssn = [460458524, 637625452, 453311896, 635285187, 455791630, 642348377, 463590491, 450730278, 641201851, 379965491];
async function getCRCDetails() {
ssn.forEach(function (item) {
if(item){
let CBCOptions = {
'method': 'POST',
'url': 'https://loanboard.houstondirectauto.com/api/Report',
'headers': {
'Content-Type': 'application/json',
'Cookie': 'ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p'
},
body: JSON.stringify({
"token": loantoken,
"action": "CBCReport",
"variables": {
ssn: item
}
})
}
request(CBCOptions, function (error, response) {
console.log(item);
console.log("CBCOPtion ", CBCOptions);
if (error) throw new Error(error);
result = (JSON.parse(response.body));
console.log("Result =", result);
CRCReport.push(result);
})
let EmployerInfoOptions = {
'method': 'POST',
'url': 'https://loanboard.houstondirectauto.com/api/Report',
'headers': {
'Content-Type': 'application/json',
'Cookie': 'ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p'
},
body: JSON.stringify({
"token": loantoken,
"action": "getEmployerInfo",
"variables": {
ssn: item
}
})
}
request(EmployerInfoOptions, function (error, response) {
console.log(response.body);
})
}
Here I need to call API request one by one.Anyone Guide me please.
I prefer use async await method for this situation
you need install and require async and request-promise
after that :
const request = require("request-promise");
const async = require("async");
let ssn = [460458524, 637625452, 453311896, 635285187, 455791630, 642348377, 463590491, 450730278, 641201851, 379965491];
async function getCRCDetails() {
//like a forEache
async.eachSeries(ssn, async (item) => {
let CBCOptions = {
method: "POST",
url: "https://loanboard.houstondirectauto.com/api/Report",
headers: {
"Content-Type": "application/json",
Cookie: "ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p",
},
body: JSON.stringify({
token: loantoken,
action: "CBCReport",
variables: {
ssn: item,
},
}),
};
let EmployerInfoOptions = {
method: "POST",
url: "https://loanboard.houstondirectauto.com/api/Report",
headers: {
"Content-Type": "application/json",
Cookie: "ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p",
},
body: JSON.stringify({
token: loantoken,
action: "getEmployerInfo",
variables: {
ssn: item,
},
}),
};
try {
let resultCBCOptions = await request(CBCOptions);
let EmployerInfoOptions = await request(EmployerInfoOptions);
console.log(resultCBCOptions)
console.log(EmployerInfoOptions)
//do pushing resultCBCOptions
//do pushing EmployerInfoOptions
} catch (error) {
console.log(error);
}
},
() => {
console.log("finished");
}
);
}
In Node the request methods that you are using are asynchronous. Meaning the runner (server) that runs the code does not wait for the request to finish and just continues to execute the next lines.
One thing that you can do is,
request.post(params).on("response", function(response) {
//....Do stuff with your data you recieve
// Make the next call here
request.post(params).on("response"), function() {
// Here you will have the second call's results
}
})
This ensures that both the API calls happen in order and only after the first one finishes.
Note:
The request library that you are using has been deprecated back in 2020. See https://github.com/request/request Hence, I would suggest you use other libraries like the standard https or http library that is shipped with node or you can use axios.
If you use a forEach loop without awaiting the results, you'll execute them all at the same time. Moreover, request library is kind of old and you need to convert its functions to return a promise.
Here's how I would do it.
const ssn = [1,2,3,4];
function download(item) {
return new Promise(function(resolve, reject) {
let options = {}; // construct your request
request(options, function (error, response) {
if(error) {
return reject(error);
}
resolve(response);
})
}
}
ssn = ssn.map(async function(item) {
let res = await download(item);
// process the result
return res;
});
You can also use the Bluebird library or get another client library such as got or axios.

Recursive function with type script

I'm playing around with promises and I'm having trouble with an asynchronous recursive promise.
The scenario is that i need to check for token validation inside a function and if the token expires i need to call the function again.
Below is the code i've done so far:
module.exports={
frstFun:()=>{...
},
secondFun:(param)=>{
return new Promise((resolve,reject)=>{
request({
url:url+'myapi',
qs:{q:param,acc_token:token},
method:'GET',
},function(err,response,body){
if(error){
//here i need to call secondFun() method..
}
});
})
}
};
I tried calling this.secondFun() but it's giving error secondFun() is not a method.
I'm not sure if a recursive retry is the best way to do this, but you could pull the function definition out of the exports object:
let secondFun = (param) => {
return new Promise((resolve, reject) => {
request({
url: url + 'myapi',
qs: { q: param, acc_token: token },
method: 'GET',
}, function (err, response, body) {
if (err) {
// secondFun(...)
}
});
})
};
module.exports = {
frstFun: () => { ... },
secondFun: secondFun
};

Categories