Hooks and Api calling - javascript

I'm calling my API through AXIOS. My response is coming back, which i can see if i check my network, but it returns empty data when I console.log:
useEffect(() => {
async function bt() {
const authAxios = axios.create({
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
const Data = await authAxios
.get('/tasks/')
.then((res) => {
console.log(res);
})
.catch((e) => {
console.log(e);
});
}
bt();
}, []);

1 - You've used an async function alongside trying to resolve the promise. Either get rid of the async and await or get rid of everything after "await authAxios"(i.e the catch and then blocks)
2 - The reason why res.data console log is blank is because res.data is undefined try changing that line to just res. Check the response Object to see if the info is there.
.then((res) => {
//console.log(res.data);
console.log(res)
setmessage(res.data);
// this.getUserUpdate(res.data)
console.log(res.data);
})
For res.data to work you need to make sure that your API creates an attribute called data for the response. If this doesn't work I recommend you also add what your back-end looks like.

As #Pyro mentioned you are mixing up 2 completly different promise-handling techniques.
You'd have to decide to either use .then()🔗 or async/await🔗
e.g.
With async/await:
useEffect(() => {
async function bt() {
const authAxios = axios.create({
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
const Data = await authAxios.get('/tasks/')
}
bt();
}, []);
Or with .then()
useEffect(() => {
function bt() {
const authAxios = axios.create({
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
const Data = authAxios.get('/tasks/').then(console.log).catch(console.log);
}
bt();
}, []);

Related

How to access property of stringified JSON?

I have this code that sends me back an url and an error. I'm trying to access the url so I can navigate to it with router.
With this code:
const redirectToStripe = async () => {
const response = await fetch(
"http://localhost:5000/create-checkout-session",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems.value),
}
)
.then((response) => response.json())
.then((response) =>
console.log("stringied response", JSON.stringify(response))
);
const { url } = await response.json();
console.log("url=", url); <--------------Doesn't execute, no console.log() readout
// window.location.href = url;
// router.go(url) <------- NEED TO FIX THIS AND UNCOMMENT;
};
I get this error:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'json')
at redirectToStripe
and this console.log() readout:
stringied response {"url":"https://checkout.stripe.com/c/pay/cs_test_a1X3r92YtZfM9H"}
That is the url I'm trying to navigate to, but I don't know how to access it in this stringified form. How do I grab the value of "url" so I can put it in the function:
router.go(url)
The later "url" console.log() never executes because of the json error (pretty sure), but I'm guessing it's the same url as the stringified one above?
I also don't know why I'm getting that error or if it's even consequential and needs to be fixed because I'm already getting the url I need. Does the error have something to do with the "Content-Type" header? Did I pick the right one? Is it something else I'm doing wrong?
Also, this is what the backend endpoint looks like if it adds context or anything.
app.post("/create-checkout-session", async (req, res) => {
// Make an array of just our Stripe Price ID and quantities
const lineItems = req.body.map((item) => {
console.log("lineItems= ", item.item.priceId, item.item.quantity);
return {
price: item.item.priceId,
quantity: item.item.quantity,
};
});
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: lineItems,
success_url: `http://localhost:8080/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `http://localhost:8080/`,
});
return res.send({ url: session.url });
});
EDITS
#pope_maverick
This code:
const redirectToStripe = () => {
const response = fetch("http://localhost:5000/create-checkout-session", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems.value),
}).then((response) => response.json());
const {url} = response.json();
// const { url } = await response.json();
console.log("url=", url);
gets me the error:
Uncaught TypeError: response.json is not a function
You forgot to return the response in your last .then callback. So your const response is actually void.
const response = await fetch(
"http://localhost:5000/create-checkout-session",
// [...]
)
.then((response) => response.json())
.then((response) => {
console.log("stringied response", JSON.stringify(response))
// ❗️ Return `response` here, or the Promise will return the returned value of `console.log` which is `void`!
return response
});
You face this issue because the API returns a string not an object so you are suppsed to use Response.text() over Response.json(), have a look the MDN Response.text()
Try below:
const redirectToStripe = async () => {
const response = await fetch(
"http://localhost:5000/create-checkout-session",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(cartItems.value),
}
)
.then(response => response.text())
.then((url) => {
const { url } = url;
console.log("url=", url);
router.go(url)
})
.catch(err => console.log(err))
};

How can I write unit test for api call with token using React, Jest and React-testing-library?

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

Unable to extract resolved value from async function

I've created a function to get the current user's data from the Reddit API, as part of a Reddit object with multiple functions.
async getCurrentUserId() {
if (userID) return userID;
const token = await Reddit.getAccessToken().then(val => {
return val;
})
const url = "https://oauth.reddit.com/api/v1/me"
const headers = {
"Authorization": `Bearer ${token}`,
"User-Agent": "blablabla",
};
const response = await fetch(url, { headers: headers });
if (response.ok) {
const jsonResponse = await response.json();
return jsonResponse.name;
}
},
However, when I try and extract the data, I keep getting a promise rather than the resolved value, and I can't seem to be able to figure it out.
const userID = Reddit.getCurrentUserId().then(val => {
return val;
}) // returns "Promise {<pending>}"
Assistance with this would be appreciated.
You either need to do your logic inside .then(), or simplify by using await:
const token = await Reddit.getAccessToken();
...
const userID = await Reddit.getCurrentUserId();

Get response.data from fetch() as variable to use in React-Native

I've seen several posts about this, so I apologize if it's a direct duplicate. The examples I've seen have the RN components built with classes. I'm using functions, and I'm new, so it's all very confusing.
const getFlights = async () => {
const token = await getAsyncData("token");
instance({
method: "get",
url: "/api/flights/",
headers: {
Authorization: `Token ${token}`,
},
})
.then(function (response) {
// console.log(response.data.results); // shows an array of JSON objects
return response.data.results; // I've also tried response.data.results.json()
})```
I just want the response returned as a variable that I can use to populate a FlatList component in RN.
const FlightListScreen = () => {
const [list, setList] = useState([]);
const flights = getFlights(); // currently returns as a promise object
Thank you for your help.
I think you have to store the response object directly to the json method. And then with that response you can store it to the variable
.then(response => { return response.json() })
.then(response => {
this.setState({
list: response
})
you are sending token without a bearer. Concrete your token with bearer like this
headers: {
Authorization: "Bearer " + token,
},
and another thing is your response class are not right this should be like this
.then((response) => response.json())
.then((responseJson) => {
API will Resopne here....
}
this is a complete example to call API with Token
fetch("/api/flights/", {
method: "GET",
headers: {
Authorization: "Bearer " + token,
},
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
setState(responseJson.VAlue);
})
.catch((error) => {
alert(error);
});

React Promise will not return a value

When trying to resolve my promise, I get the error "Objects are not valid as a React child (found: [object Promise])."
In the console.log after my API request in GetCardsFromBoard(), the typeOf() my response is string and it prints out the data to the console. But in TrelloTester(), the console shows that my response is still Promise<pending> and I get the error.
I've tried so many configurations but I can't get my promise to resolve, thanks for any help!
const fetch = require('node-fetch');
export async function GetCardsFromBoard(board) {
let cards = await fetch(
baseURL+'boards/'+board+'/cards?key='+key+'&token='+token,
{
method: 'GET',
headers: {
'Accept': 'application/json'
}
})
.then(response => {return response.text()})
.catch(err => console.error(err));
console.log(typeof(cards), cards); //prints "string" type and then the entire json response
return cards;
}
export function TrelloTester() {
let bodyStr = GetCardsFromBoard(boardID);
console.log("resp: ", bodyStr); //shows Promise<pending>, but with the correct response value inside
return (
<BigCard header=" " body={bodyStr}/>
);
}
export default TrelloTester;
GetCardsFromBoard returns a Promise. async/await is just sugar on top of promises and doesn't actually make the code any less asynchronous. Therefore, your TrelloTester component will still have to treat the function as a Promise.
Note that I removed the then in your promises; if you're using async/await then you can just await all the promises!
export async function GetCardsFromBoard(board) {
try {
const cards = await fetch(
baseURL+'boards/'+board+'/cards?key='+key+'&token='+token,
{
method: 'GET',
headers: {
'Accept': 'application/json'
}
})
return await cards.text();
} catch(e) {
console.log(e);
}
}
In you component, since this is asynchronous, I recommend treating it as an effect and using the useEffect hook in conjunction with the useState hook.
import React, { useEffect, useState } from "react";
export function TrelloTester() {
const [bodyStr, setBodyStr] = useState("");
useEffect(() => {
cont getCards = async () => {
const cards = await GetCardsFromBoard(boardID);
setBodyStr(cards);
}
getCards();
}, []);
return bodyStr ? (
<BigCard header=" " body={bodyStr}/>
) : "Loading...";
}
export default TrelloTester;
http response needs to be converted to json, use json() method.
let cards = await fetch(
baseURL+'boards/'+board+'/cards?key='+key+'&token='+token,
{
method: 'GET',
headers: {
'Accept': 'application/json'
}
})
.then(response => {return response.json()})
.catch(err => console.error(err));

Categories