Problem with axios and activeCampaign api - node.js

i have created firebase cloud function to create contact in activeCampain. I have problem with catch errors from activeCampaign. If i sent request direct to activeCampain from insomnia everything works correctly, but if i use firebase cloud function with axios something goes wrong.
I will show the code.
I created a contact before and now it makes another query with the same data directly to activeCampaign api:
and i get expected result. But if made same request by firebase function i get properly status code but i don't see errors response from activeCampaign
FirebaseCloud function code:
const functions = require("firebase-functions");
const axios = require("axios");
const cors = require("cors")({ origin: true });
const addTagToContact = async (contactId: string, tagId: string) => {
try {
await axios({
method: "post",
url: "https://xyz.api-us1.com/api/3/contactTags",
headers: {
"Api-Token": "api-token",
},
data: {
contactTag: {
contact: contactId,
tag: tagId,
},
},
enter code here
});
} catch (e) {
console.error(e);
}
};
export const createNewContact = functions.https.onRequest((request: { body: any; }, response: { status: (arg0: number) => void; send: (arg0: { response?: unknown; status?: string; }) => void; }) => {
cors(request, response, async () => {
const newContactData = request.body;
if(!newContactData.email || !newContactData.fieldValues) {
return response.send({
response: 'No contact data provided'
})
}
try {
const responseActiveCampaign = await axios({
method: "post",
url: "https://xyz.api-us1.com/api/3/contacts",
headers: {
"Api-Token": "api-token",
"Content-Type": "application/json"
},
data: {
contact: newContactData,
},
});
console.log('response active campaign console log', responseActiveCampaign)
await addTagToContact(responseActiveCampaign.data.contact.id, "1")
return response.send({
response: responseActiveCampaign.data
})
} catch (error) {
console.error('catch error', error);
response.status(500);
response.send({
response: error,
});
}
});
});
response from this query:
How can i fix it? I would like to get error response from activeCampaign to use on my frontend

the catch should be like this:
catch (error) {
console.error('catch error', error);
response.status(500);
response.send({
response: error.response.data,
});
}

Related

How to create mock function and have good coverage

I am finding it difficult to have code coverage and mocking request and few functions
cf.service.ts
import { omit } from "lodash";
var request = require('request');
const callForwardConfig = require('../../config/callForwardConfig').callForwardConfig;
import logger from "../../utils/logger";
import { SetCallforwardAs } from '../../interfaces/callforward.interface';
export async function appSerGetCallForwardingState(sid: string, token: string) {
try {
return await callForwardApiCall(sid, token).then((res) => {
return res;
})
} catch (e: any) {
throw new Error(e);
}
}
function callForwardApiCall(sid: string, token: string) {
let callforwardUrl = callForwardConfig.url.as;
return new Promise((resolve, reject) => {
request(`${callforwardUrl}?userId=${sid}`, {
method: 'get',
strictSSL: false,
mode: 'no-cors',
json: true,
headers: { 'Content-Type': 'application/json', Authorization: token},
}, (err: any, response: any, body: any) => {
if (err) {
reject(JSON.stringify(err))
} else {
resolve(body);
}
})
});
}
export async function putAppserCallForward(token: string, callForwardObj: SetCallforwardAs) {
return await updateCallForwardAs(token, callForwardObj).then((res) => {
return res;
})
}
async function updateCallForwardAs(token: string, callForwardObj: SetCallforwardAs) {
let callforwardUrl = callForwardConfig.url.as;
return await new Promise((resolve, reject) => {
let body = {
clusters: callForwardObj.clusters,
name: callForwardObj.name,
destination: callForwardObj.destination,
user: callForwardObj.user
}
logger.info(`App server update cfwrd Request object - ${JSON.stringify(body)}`)
request(`${callforwardUrl}`, {
method: 'put',
strictSSL: false,
mode: 'no-cors',
json: true,
body: body,
headers: { 'Content-Type': 'application/json', Authorization: token},
}, (err: any, response: any, body: any) => {
if (err) {
logger.error(`App server call forward update failure USER - ${callForwardObj.sid}`, JSON.stringify(err));
reject(JSON.stringify(err));
} else {
if (!body['success'])
logger.error(`App server call forward update failure USER - ${callForwardObj.sid} - Error - ${JSON.stringify(body)}`);
else
logger.info(`App server call forward update success USER - ${callForwardObj.sid}`);
resolve(body);
}
})
});
}
I have written test as below:
import createServer from "../../utils/server";
const appserService = require('../../service/provider/appser.service');
const request = require('request');
const app = createServer();
jest.mock('request');
const sid = 'A121';
describe("appserver service", () => {
it("appSerGetCallForwardingState", async () => {
const callForwardApiCallMock = jest.spyOn(appserService, 'callForwardApiCall');
callForwardApiCallMock.mockImplementation(() => {
return Promise.resolve('success');
});
appserService.appSerGetCallForwardingState(sid, 'token').then((res: any) => {
expect(res).toBe('success');
});
});
it("callForwardApiCall", async () => {
request.get.mockResolvedValue({ "success": "true" });
appserService.callForwardApiCall(sid, 'token').then((res: any) => {
expect(res).toBe({ "success": "true" });
});
});
it("callForwardApiCall error", async () => {
request.get.mockRejectedValue(new Error('error'));
appserService.callForwardApiCall(sid, 'token').then((res: any) => {
expect(res).toBe({ "success": "true" });
});
});
});
I am struggling to have good code coverage at - least 90%.
request object also needs to be mocked, and functions are not being exported like callForwardApiCall also not able to access from test file
Here is the report:

AWS Lambda not calling third party api in loop

i am using aws lambda and i am calling third party server using request library. this library on outside the loop but on loop its not hitting even i am not getting any error or result. and i also checked on server there is no hitting
below is my code with console
exports.handler = async (event) => {
try {
let transactionList = [];
// event.body is json form object with keys and values that we send
userBrokers.forEach(async (brokers) => {
const userStocks = 50;
const qty = (qtyPercentage * userStocks) / 100;
console.log("function before api call")
request.post({
headers: {
'content-type': 'application/x-www-form-urlencoded',
"Apca-Api-Key-Id": brokers.api_key,
"Apca-Api-Secret-Key": brokers.secret_key
},
url: 'https://paper-api.alpaca.markets/v2/orders',
json: {
symbol,
qty,
side: orderType,
type: marketType,
time_in_force
}
}, function (error, response, body) {
if (error) {
console.log("api call error")
transactionList.push({
transactionSuccess: false,
reason: error,
userId: brokers.user_id,
documentId: brokers._id
})
}
else {
console.log("api response")
if (response.statusCode == 200) {
transactionList.push({
brokerOrderId: body.id,
symbol: body.symbol,
orderType: body.order_type,
marketType: body.side,
transactionSuccess: true,
userId: brokers.user_id,
documentId: brokers._id
})
}
else {
transactionList.push({
transactionSuccess: false,
reason: body.message,
userId: brokers.user_id,
documentId: brokers._id
})
}
}
});
})
console.log("function before response")
return {
statusCode: 200,
body: JSON.stringify(transactionList),
};
} catch (error) {
console.log("function catch block")
return {
statusCode: 200,
body: JSON.stringify(error.message),
};
}};
and i get below console.
function before api call
function before response
and response from lambda
status: 200 and message: []
The problem is that you're trying to execute an async method in a forEach but you have no way of enforcing Lambda to wait for the loop to finish. You should switch your forEach to a map and await all the promises:
Bad:
arr.forEach(async (val) => {})
Good:
const arrOfResults = await Promise.all(arr.map(async (val) => {}))

i'm getting isssue while calling API in Useeffect in reactJs

I'm calling two methods in useeffect but when api1 get called it get executed till await axios.put and then api2 get called without getting the response from api1. And after getting a reponse from api2 it goes to api1 reponse and gets a reponse as undefined
useEffect(() => {
api1();
api2();
}, [])
const api1 = async () => {
try {
var requestModel = JSON.stringify({ UserId: userid, MenuName: menuname });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.put(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
//setapidata(response.data);
}
});
} catch (error) {
console.error(error.message)
}
}
const api2= async () => {
try {
var requestModel = JSON.stringify({ UserID: userid });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.post(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
setapidata(response.data);
GetApis();
}
});
} catch (error) {
console.error(error.message)
}
}
If you want to wait for the api1 to execute before api2 is called you need to change the code for useEffect as below
useEffect(async() => {
await api1();
await api2();
}, [])
or
useEffect(() => {
api1().then(() => api2());
}, [])
To handle errors properly use try-catch block inside the useEffect if using await or use catch block if using .then
Also, another suggestion, if you are using a function inside useEffect make sure either the function is defined inside the same useEffect block or it is memorized either via useCallback or useMemo

Using React, NodeJS, and Postgres: Having trouble being able to delete and updating todos

I am creating simple todo app with postgre and react.
The server side the delete and update are defined as below.
app.put("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const { description } = req.body;
const updateTodo = await pool.query(
"update todo set description = $1 where todo_id = $2",
[description, id]
);
res.json("todo updated !!");
} catch (error) {
console.error(error.message);
}
});
// delete todo
app.delete("/todos/:id", async (req, res) => {
try {
const { id } = req.params;
const deleteTodo = await pool.query("delete from todo where todo_id = $1", [
id,
]);
res.json("todo deleted !!");
} catch (error) {
console.error(error.message);
}
});
On the front end (React) this is how I am calling the update and delete
const updateDescription = async () => {
try {
handleClose();
const body = { description };
const response = fetch(`http://localhost:3000/${todo.todo_id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
console.log(response);
} catch (error) {
console.log(error.message);
}
};
Delete todo is in the other component.
const deleteTodo = async (id) => {
try {
const deleteTodo = await fetch(`http://localhost:3000/${id}`, {
method: "DELETE ",
});
console.log(deleteTodo);
setTodods(todos.filter((todo) => todo.todo_id !== id));
} catch (error) {
console.log(error.message);
}
};
So when I am doing delete or put request its not updating it in the DB.
On the browser console I am getting this error.
Failed to execute 'fetch' on 'Window': 'DELETE ' is not a valid HTTP method.
Edited
Response {type: "cors", url: "http://localhost:3000/3", redirected: false, status: 404, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 404
statusText: "Not Found"
type: "cors"
url: "http://localhost:3000/3"
__proto__: Response
For insert todo its working but for delete and put request its not updating in the database.
So can somebody tell me whats going wrong here ?
There is a space after DELETE, correct it should work properly. Even if its a simple todo App, its always good practice to create an enum or const when we are dealing with fixed string, i.e., we know the string would not change so that we can have consistency and skip over these kind of issues.
const METHOD = {
GET: "GET",
PUT: "PUT",
POST: "POST",
DELETE: "DELETE"
};

How to convert fetch to axios

I have the following piece of code which is working perfect. However, my task is to replace fetch with axios. can you please guide, what would be the correct replacement of code in axios?
const create = async (credentials, software) => {
return await fetch('/api/software/create', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
credentials: 'include',
body: JSON.stringify(software)
})
.then((response) => {
return response.json()
}).catch((err) => console.log(err))
}
create({ t: jwt.token }, data)
.then((data) => {
if (data.error) {
this.setState({ error: data.error })
} else {
this.props.dispatch(initSoftware()); //if successful get the list of softwares in redux store
}
})
The data variable is an object which hold the req.body equivalent...
The above code is written in react and the create() is called within onSubmit eventhandler.
I am sure if I use axios the create() would be eliminated.. but how? Please guide..
It shouldn't be too different than what you currently have but something like this...
const create = async (credentials, software) => {
return await axios({
url: '/api/software/create'
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + credentials.t
},
withCredentials: true,
data: JSON.stringify(software)
})
.then((response) => {
return response.data;
}).catch((err) => console.log(err))
}
create({ t: jwt.token }, data)
.then((data) => {
if (data.error) {
this.setState({ error: data.error })
} else {
this.props.dispatch(initSoftware()); //if successful get the list of softwares in redux store
}
})
Note that the data you would be looking for should be in a property called data.
For more, check out the API references here.
2021 answer: just in case you land here looking for how to make GET and POST Fetch api requests using async/await or promises as compared to axios.
I'm using jsonplaceholder fake API to demonstrate:
Fetch api GET request using async/await:
const asyncGetCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncGetCall()
Fetch api POST request using async/await:
const asyncPostCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
});
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncPostCall()
GET request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
POST request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
GET request using Axios:
const axiosGetCall = async () => {
try {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosGetCall()
POST request using Axios:
const axiosPostCall = async () => {
try {
const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts', {
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosPostCall()

Resources