I have this piece of code which makes a GET HTTP request.
When using fetch, it works but with axios it never finishes.
What I tried so far is something like this:
getParentAssetTemplateList = async (tenantId: string, signal?: AbortSignal): Promise<any> => {
const headers = {
tenantId: tenantId,
...this.defaultHeaders
};
const url = getEndpoint('/asset-templates/dropdown/flat');
// const response = await fetch(url, {
// signal,
// headers
// }).then((res) => res.json());
// console.log('response: ', response);
// return response;
const response = await axios.get(url, {
signal,
headers
});
console.log('response: ', response.data);
return response.data;
};
What I mean by finishes is, when using Fetch, the debug point reaches console.log.
But with Axios, it doesn't reach the console.log line but when I check in network tool I see the response coming as 200 OK with the expected data.
Related
I am writing a simple post request in a Firebase Cloud function, with Axios. This function calls an API endpoint and gets an object of profile details as response. My problem is to correctly return the response to the client.
In the code below, the Cloud Function logs the result correctly. But I can't figure out how to correctly return it to the client from the client-side callGetProfile() function. (Which runs inside a Vue3 method.)
I am probably missing something obvious but am very new to Node.js and HTPP requests.
Thanks for any help!
// MY FUNCTION IN NODE.JS (Firebase Cloud Functions)
exports.getProfile = functions.https.onCall((data, context) => {
var postData = {
profile_id: "xxxxxxxxxxxxxxxxx", //hardcoded here for testing but should be passed in "data" arg.
profile_type: "personal",
};
let axiosConfig = {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'X-API-KEY': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX'
}
};
axios.post('xxxxxxxxxxxxxxxxxxxxxxxxxxxxx', postData, axiosConfig)
.then((res) => {
console.log(res.data) // this works, I get all the data correctly!!
return res // also tried res.data
})
.catch((err) => {
console.log("AXIOS ERROR: ", err);
})
});
// MY FUNCTION CLIENT SIDE (Vue3 method)
const functions = getFunctions();
const callGetProfile() = httpsCallable(functions, "getProfile");
callGetProfile()
.then((result) => {
console.log(result.data) // this doesn't work, data is "null"
})
.catch((e) => console.log(e));
Here is the function that I wanna test, it takes a token and a description as props. Normally in React code, I can get token from useContext.
export const updateUserProfileAbout = async (
token,
description
) => {
const dataUpdateTemplateDescriptionRes = await patchData(`me/`, token, {
about:description,
});
const dataUpdateTemplateDescriptionJson = await dataUpdateTemplateDescriptionRes.json();
return dataUpdateTemplateDescriptionJson;
};
And here is my custom patchData function:
const patchData = async (urn, token, data = "") => {
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${token.access}`,
};
const body = data ? JSON.stringify(data) : null;
let response;
if (body) {
response = await fetch(`${host}/api/${urn}`, {
method: "PATCH",
headers,
body,
});
} else {
response = await fetch(`${host}/api/${urn}`, {
method: "PATCH",
headers,
});
}
if (!response.ok) throw new Error(response.status);
return response;
};
You are right. You don't need the token. All you need to do for mocking the fetch is the following:
jest.spyOn(global, 'fetch').mockImplementationOnce(
jest.fn(() => Promise.resolve()) as jest.Mock);
If you want to retrieve a specific object from a json response, you can use:
jest.spyOn(global, 'fetch').mockImplementationOnce(
jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve({ myObject }) })) as jest.Mock);
You can also reject it to trigger the error catch:
jest.spyOn(global, 'fetch').mockImplementationOnce(
jest.fn(() => Promise.reject()) as jest.Mock);
If you want to return something multiple times, change the mockImplementationOnce to whatever you need (maybe mockImplementation, for returning it every time you call it).
If you also want to expect the call of the fetch just add a constant:
const myFetch = jest.spyOn(global, 'fetch').mockImplementationOnce(
jest.fn(() => Promise.reject()) as jest.Mock);
You can then expect it via: expect(myFetch).toBecalledTimes(1);
After one more day of researching, I might be wrong though but I don't think I have to care about token or authorization when unit testing for front-end. All I need is jest.fn() to mock function and jest.spyOn(global, "fetch") to track fetch API.
For more information, here are some references that I read:
https://codewithhugo.com/jest-fn-spyon-stub-mock/
https://dev.to/qmenoret/mocks-and-spies-with-jest-32gf
https://www.pluralsight.com/guides/how-does-jest.fn()-work
https://www.loupetestware.com/post/mocking-api-calls-with-jest
I am trying to make an API call from my JavaScript app to an endpoint in another application.
When I call the endpoint I get the status code and the message, but I cannot access the response body in any way. I have tried different ways to get the data, but nothing seems to work for me.
In the method "someAction", I want to use the data in the response/result from the API call. I added the outputs that the single log-lines print in the code.
How can "result" be undefined while "result.status/message" are defined?
What do I have to do in order to get the data/body as JSON or String?
The API itself is tested and returns data when tested in postman.
Thanks for your help!
const request = require('request')
let callEndpoint = () => {
return new Promise((resolve, reject) => {
const url = `https://my.api.com/endpoint`
const requestOptions = {
url: url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
'My-API-Authorization': '123456789'
},
json: true,
strictSSL: false
}
request.get(requestOptions, (err, response) => {
if(err)
{
return reject(err);
}
return resolve(response);
});
});
}
let someAction = () => {
callEndpoint()
.then(result => {
logger.logInfo(result.statusCode) // => 200
logger.logInfo(result.statusMessage) // => OK
logger.logInfo(result) // => undefined
logger.logInfo(result.toString()) // => [object Object]
logger.logInfo(result.body) // => undefined
logger.logInfo(result.data) // => undefined
JSON.parse(result.toString()) // => Unexpected token o in JSON at position 1
JSON.parse(result) // => Unexpected token o in JSON at position 1
// DO SOME STUFF WITH THE RESULT
})
}
I'm kind of new to JS and can't figure out how to make the following work:
I'd like to run functions (for test reasons console) in the different stages of the fetch API. Like run console when fetch started because of click –> then when fetch received a response (text) -> then when the fetch response has been parsed -> and finally when the parsed response text has replaced the HTML of an existing DOM-element.
var doFetch = (url) => {
fetch(url, {
method: "GET",
headers: new Headers({
'X-Requested-With': 'fetch'
})
}){
console.log("fetch request started because of click on element");
}
.then(response => response.text();
console.log("fetch request has received the response text");
)
.then(response => {
let content = new DOMParser().parseFromString(text, "text/html");
console.log("the received request response text was DOMparsed");
})
.then(response => {
let main = content.querySelector('main').innerHTML;
console.log("the parsed response content replaced current HTML");
}
};
Any tips on how to correct the code would be gladly welcomed!
each then block will execute if previous then block return.
Your first console.log statement should be at the start of the doFetch function. It cannot be written where it is currently written in your code.
You should also chain a catch block at the end to catch any errors that might occur in the promise chain.
As a side note, you should use const or let keywords to declare variables instead of var.
const doFetch = (url) => {
console.log("fetch request started because of click on element");
fetch(url, {
method: "GET",
headers: 'X-Requested-With': 'fetch'
})
.then(response => {
console.log("fetch request has received the response text");
return response.text();
})
.then(response => {
console.log("the received request response text was DOMparsed");
return new DOMParser().parseFromString(text, "text/html");
})
.then(response => {
let main = content.querySelector('main').innerHTML;
console.log("the parsed response content replaced current HTML");
})
.catch(error => console.log(error));
};
In order to do chaining you need to return from each .then block. Aslo your first console.log() post the fetch function had incorrect syntax
var doFetch = (url) => {
fetch(url, {
method: "GET",
headers: 'X-Requested-With': 'fetch'
})
.then(response => {
console.log("fetch request has received the response text");
return response.text();
})
.then(response => {
let content = new DOMParser().parseFromString(text, "text/html");
console.log("the received request response text was DOMparsed");
return content
})
.then(content => {
let main = content.querySelector('main').innerHTML;
console.log("the parsed response content replaced current HTML");
});
console.log("fetch request started because of click on element"); // This will be executed first
};
I am trying to load a data from my firebase backend but getting this error
Uncaught (in promise) TypeError: response.json is not a function
my code is as below :
import axios from 'axios';
export const loadData = ({ commit }) => {
console.log('getting data from server...');
axios
.get('data.json')
.then(response => response.json())
.then(data => {
if (data) {
const stocks = data.stocks;
const stockPortfolio = data.stockPortfolio;
const funds = data.funds;
const portfolio = {
stockPortfolio,
funds
};
commit('SET_STOCKS', stocks);
commit('SET_PORTFOLIO', portfolio);
console.log('Commit done ');
}
});
};
however, if I try response.data instead of response.json it works and successfully loads the data, so I am curious what the difference is and why the first one doesn't work.
Because of the axios package, it has a specific response schema https://github.com/axios/axios#response-schema
The response for a request contains the following information.
{
// `data` is the response that was provided by the server
data: {},
// `status` is the HTTP status code from the server response
status: 200,
// `statusText` is the HTTP status message from the server response
statusText: 'OK',
// `headers` the headers that the server responded with
// All header names are lower cased
headers: {},
// `config` is the config that was provided to `axios` for the request
config: {},
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance in the browser
request: {}
}
With axios you don't need an extra .json() .Responses are already served as javascript object, no need to parse, simply get response and access data. You could use directly something like
axios.get('/user/12345')
.then(function (response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
You only need to use the Body.json() method if you are trying to resolve the promise from a Response stream. You may read more about it on the documentation. One use case of doing so would be when you are making a HTTP request using the fetch API, whereby you will have to call Body.json() to return the response body.
let response = await fetch(url);
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
let json = await response.json();
} else {
alert("HTTP-Error: " + response.status);
}
For axios, you only need to resolve the promose after making a GET request
axios.get(url[, config])
and thus, the following code below works, as the returned response body is handled within the .then() block when you resolve the promise.
axios
.get('data.json')
.then(response => console.log(response.data))
const CollectData = async () => {
let result = await fetch('http://localhost:5400/Enquiry', {
method: "post",
body: JSON.stringify({ name, email, contact, message }),
headers: {
"Content-Type": "application/json",
}
});
result = await result.json();
console.log(result);
if (result) {
navigate("/");
}