I am using third party API. The way it works is:
I send post request then Token is returned in response.
Then i use that Token to check status. Afterwards, report is returned in response
In postman, i make both calls separately and it is working, but in Axios I have 1 async function and 2 await Promises.
Postman(NodeJs - Axios) looks like this:
For getting Token:
var data = JSON.stringify({
"security": {
"pLogin": "a",
"pPassword": "io"
},
"data": {
"pHead": "005",
"pCode": "00433",
"pLegal": 1,
"pClaimId": "z4LpXRWZKecSnL-FQtgD",
"pReportId": 8,
"pReportFormat": 1
}
});
var config = {
method: 'post',
url: 'http://10.22.50.10/report/',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
For getting Report with the token:
var data = JSON.stringify({
"data": {
"pHead": "005",
"pCode": "00433",
"pToken": "kgqjismxdrpjnjaqnlnbmovcsvnkarfd",
"pClaimId": "z4LpXRWZKecSnL-FQtgD",
"pReportFormat": 1
}
});
var config = {
method: 'post',
url: 'http://10.22.50.10/report/status',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
My async function with Axios:
/* 1. Searching for client in database (Full name is used, but can be changed)*/
const client = await client.findOne({
name: body.name,
family_name: body.family_name,
patronymic: body.patronymic
});
if (!client) {
return res.status(401).json({ message: "Client is not registered" });
}
/* 2. If client was found in database, make an API call */
let credit_report;
try{
credit_report = await axios.post(
'http://10.22.50.10/report',
{
security: {
pLogin: 'a',
pPassword: 'io',
},
data: {
pHead: "005",
pCode: "00433",
pLegal: 1,
pClaimId: client.claim_id,
pReportId: 8,
pReportFormat: 1
}
},
{
headers: {
'content-type': 'application/json'
}
}
);
}catch(err){
return res.status(400).json({errorMessage: err.message})
}
// await new Promise(resolve => setTimeout(resolve, 3000));
if(!credit_report.data.data.token) return res.status(400).json({message: credit_report.data});
const credit_report_status = await axios.post(
'http://10.22.50.10/report/status',
{
data: {
pHead: "005",
pCode: "00433",
pToken: credit_report.data.data.token,
pClaimId: client.claim_id,
pReportFormat: 1
}
},
{
headers: {
'content-type': 'application/json'
}
}
);
console.log(credit_report_status)
if(credit_report_status.data.data.result == '05000') return res.status(200).json({ message: 'Client fetched.', clientData64: credit_report_status.data.data.reportBase64});
else return res.status(400).json({message: credit_report_status.data})
When I am using Postman to check my module, it is saying Error 400 Bad Request
Related
the code below is the first request for get list data
mounted() {
this.getList()
},
methods: {
handleClick(row) {
console.log(row.id)
console.log(row.url)
this.$router.push({ name: 'Main', query: { id: row.id } })
},
getList() {
axios
.get('/api/v1/requests/all', {
params: {
userId: this.$store.state.userInfo.id,
},
})
.then(response => {
let moment = require('moment')
for (var item of response.data.data) {
item.createdAt = moment(item.createdAt).format(
'YYYY-MM-DD HH:mm:ss',
)
}
this.items = response.data.data
})
.catch(error => {
console.log(error)
})
}
my interceptor
axios.interceptors.response.use(
function (response) {
return response
},
async function (error) {
const originalRequest = error.config
if (error.response.status === 401 && !originalRequest._retry) {
error.response.config._retry = true
sessionStorage.removeItem('access-token')
let headers = {
grant_type: 'refresh_token',
Authorization: sessionStorage.getItem('refresh-token'),
}
axios
.post('/api/v1/users/refresh_token', {}, { headers: headers })
.then(response => {
let token = response.data.data
sessionStorage.setItem('access-token', token)
originalRequest.headers['Authorization'] = token
originalRequest.headers['grant_type'] = 'grant_type'
return axios.request(originalRequest)
})
.catch(error => {
console.log(error)
alert('blablabla.')
})
}
return Promise.reject(error)
},
)
the flow is i understand
1.token expired
2.move to list page
3.mounted hook is request data
4.getList -> axios get('~~request/all')
5.interceptor->axios post('~~~refresh_token')
6.re request with new token(request/all)
7.re request is 200, but not update list page
i'd really appreciate your help :)
Seems like you need to return the second request (await for result and return). Right now the result of second request seems to be ignored
axios.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
error.response.config._retry = true;
sessionStorage.removeItem("access-token");
let headers = {
grant_type: "refresh_token",
Authorization: sessionStorage.getItem("refresh-token"),
};
const [secondError, res] = await axios // await here
.post("/api/v1/users/refresh_token", {}, { headers: headers })
.then(async (response) => {
let token = response.data.data;
sessionStorage.setItem("access-token", token);
originalRequest.headers["Authorization"] = token;
originalRequest.headers["grant_type"] = "grant_type";
return [null, await axios.request(originalRequest)];
})
.catch((err) => {
console.log(err);
alert("blablabla.");
return [err, null];
});
// Handle here
if(secondError) {
return Promise.reject(secondError);
}
return Promise.resolve(res)
}
return Promise.reject(error);
}
);
The above solution worked for me perfectly. here's the modified code that I used for my requirement.
export default function axiosInterceptor() {
//Add a response interceptor
axios.interceptors.response.use(
(res) => {
// Add configurations here
return res;
},
async function (error) {
const originalRequest = error.config;
let secondError, res
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
[secondError, res] = await axios({
method: "POST",
url: `${baseURL}/account/token/refreshtoken`,
withCredentials: true,
headers: { "Content-Type": "application/json" },
})
.then(async (response) => {
//handle success
return [null, await axios.request(originalRequest)];
}).catch(function (error) {
console.error(error)
});
}
if (secondError) {
return Promise.reject(secondError);
}
return Promise.resolve(res)
}
);
}
I am writing Test case using JEST in NodeJs inside AzureFunction.
Im trying to mock JWT module outcome inside my index.test.js , however its not working and getting timedout. I wonder is it the return datatype mismatch? How to set response similar to cb of jwt verify method?
Here is my sample code. Please suggest!
Index.js
const JWT = require('./jwtDecoder')
module.exports = function(context, req) {
try {
JWT(req.body, process.env.jwtsecret, function(err, decoded) {
if (err) {
context.log("Invalid JWT::" + req.body);
context.res = {
headers: {
'Content-Type': 'application/json'
},
status: 400,
body: {
"error": err
}
};
context.done();
} else {
context.log("JWT Authentication Successful:");
context.res = {
headers: {
'Content-Type': 'application/json'
},
status: 200,
body: {
"message": "success"
}
};
context.done();
}
});
} catch (err) {
context.log("Exception in main function, PushHttpFunction:" + err);
context.res = {
headers: {
'Content-Type': 'application/json'
},
status: 500,
body: {
"error": err
}
};
context.done();
}
}
jwtDecoder.js
'use strict';
module.exports = (body, secret, cb) => {
console.log('inside jwtDecoder');
if (!body) {
return cb(new Error('invalid jwt data'));
}
require('jsonwebtoken').verify(body.toString('utf8'), secret, { algorithm: 'HS256' }, cb);
};
index.test.js
let indexTest = require('../index')
const { runStubFunctionFromBindings } = require('stub-azure-function-context')
let JWT = require('../jwtDecoder')
jest.mock("../jwtDecoder.js")
/* verify.mockImplementation(() => () => ({
err: new Error('invalid jwt data'),
decoded: 'ok'
})); */
JWT.mockImplementation(() => new Promise(function(resolve, reject) {
resolve('ok');
}));
beforeAll(() => {
process.env = Object.assign(process.env, {
NODE_ENV: "test",
});
});
describe('Simple Testing', () => {
test('return 200 by mocking simpleFunc response" ', async() => {
let request = {
body: "dummy.jwt.zT5p"
};
const context = await runStubFunctionFromBindings(indexTest, [
{ type: 'httpTrigger', name: 'req', direction: 'in', data: request },
{ type: 'http', name: 'res', direction: 'out' },
], new Date());
console.log('mockedResp::', context);
expect(context.res.status).toEqual(200);
}, 30000);
});
Basically you are mocking wrong, you can keep only this line:
jest.mock('./jwtDecoder.js', () => (res, req, cb) => cb(null, 'ok'))
as you need to mock callback
and remove all this part:
jest.mock("../jwtDecoder.js")
JWT.mockImplementation(() => new Promise(function(resolve, reject) {
resolve('ok');
}));
I'm successfully authenticating with the server, sending my graphql request and receiving a response. However the response isn't quite right.
This is just a simple nodejs, axios, graphql situation. I can get a correct respose via postman or curl but not with node. I've tried fetch as well to no avail. Am I doing something wrong? This is for the producthunt api, the api explorer is located at here
require('dotenv').config()
const axios = require("axios");
const PH_KEY = process.env.PH_KEY;
const PH_SECRET = process.env.PH_SECRET;
const BASE_URL = process.env.BASE_URL;
const AUTH_URL = process.env.AUTH_URL;
const GRAPHQL_URL = process.env.GRAPHQL_URL;
const PH = axios.create({
baseURL: BASE_URL,
responseType: 'json',
headers: {
// 'Accept': 'application/json, text/plain, gzip, deflate, */*',
'Content-Type': 'application/json'
},
})
let TOKEN = 'Bearer '
const getAuth = async () => {
return await PH({
url: AUTH_URL,
method: "post",
data: {
client_id: `${PH_KEY}`,
client_secret: `${PH_SECRET}`,
grant_type: "client_credentials"
}
})
.then((res) => {
console.log('auth status ', res.status)
return res.data.access_token
})
.then((res) => {
TOKEN += res
console.log(TOKEN)
})
.catch((err) => {
console.log(err)
})
}
const getHunt = async () => {
await getAuth()
PH.defaults.headers.common['Authorization'] = TOKEN
return await PH({
url: GRAPHQL_URL,
method: 'post',
data:
{
query: `
query posts {
posts(order: RANKING, first: 1) {
edges {
node {
name
votesCount
user {
name
}
createdAt
}
}
}
}
`
}
})
.then((res) => {return res})
.then((res) => {
console.log(res.data)
return res.data
})
.catch((err) => {
console.log(err)
})
}
const Main = async () => {
await getHunt()
}
Main()
This is the output I receive in node:
[Running] node "/Users/fireinjun/Work/YAC/yac-ph-tophuntfunction/app.js"
auth status 200
Bearer #################################################
{ data: { posts: { edges: [Array] } } }
Here's what I'm expecting:
{
"data": {
"posts": {
"edges": [
{
"node": {
"name": "Trends by The Hustle",
"votesCount": 125,
"user": {
"name": "Jack Smith"
},
"createdAt": "2019-06-04T07:01:00Z"
}
}
]
}
}
}
I was accessing the data incorrectly! Apparently I needed to see the res.data.data.posts.edges[0]
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()
I'm following this tutorial, I got to the point to send an HTTP request to the fcm endpoint, but I'm getting the following error:
{
error:
{
code: 400,
message: 'Request contains an invalid argument.',
status: 'INVALID_ARGUMENT'
}
}
Instead of sending the request using curl I'm using a cloud function using node.js | express with the following code:
exports.messages = function (req, res) {
const api = 'https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send';
const headers = {
'Accept': 'application/json',
'Content-type': 'application/json',
};
return getAccessToken().then((accessToken) => {
headers.Authorization = `Bearer ${accessToken}` // <-- accessToken is OK
const { title, body, token } = req.body;
return fetch(api, {
headers,
method: 'POST',
body: JSON.stringify(
{
'message': {
'token': token, // <-- this is the client fcm token
'notification': {
'title': title,
'body': body
}
}
}
)
}).then(res => res.json()).then(data => {
console.log(data);
res.sendStatus(200);
}).catch((error) => {
console.error(error);
});
});
}
Where the token is an OAuth 2 token for my service account
function getAccessToken() {
return new Promise(function (resolve, reject) {
var key = require('../keys/service-account.json');
var jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
[
'https://www.googleapis.com/auth/firebase',
'https://www.googleapis.com/auth/firebase.database',
'https://www.googleapis.com/auth/firebase.messaging',
],
null
);
jwtClient.authorize(function (err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
what am I missing here? any advice will be appreciated
I just realized I copied the uri for the fcm endpoint from the tutorial. I changed it to:
const api = 'https://fcm.googleapis.com/v1/projects/{project-Id}/messages:send';
and it worked!