Nested async axios - axios

I need to get the data from the second nested axios call and be able to use it outside of the init function
const init = async () => {
await axios.get(generateSessionUrl())
(({ data }) => data)
(async ({ session_id }) => {
const godSignature = await md5(`${config.devId}getgods${config.authKey}${date}`);
await axios.get(`https://api.smitegame.com/smiteapi.svc/getgodsjson/${config.devId}/${godSignature}/${session_id}/${date}/1`)
((data) => {
setGods(data);
console.log(data.data[0].Ability_1.Description.itemDescription)
let info = data.data;
return info
})
})
};

Related

fetch data from array of foreign keys

I have two collections in my MongoDB restaurants and dishes ,I'm trying to enter to a specific restaurant and fetch it's dishes according to the foreign keys id in "dishes" array in restaurant object
this is an example how restaurant look like:
[
{
"_id": "63a877556959f4b58c5042cf",
"name": "Claro",
"chef": "Ran Shmueli",
"establishYear": 1990,
"dishes": [
"63aeb686a8b59bf5aac97702",
"63aeb923a8b59bf5aac97705",
"63aeb9d0a8b59bf5aac97708",
"63aebad9a8b59bf5aac9770b",
"63aebc8aa8b59bf5aac9770e",
"63aebe21a8b59bf5aac97711",
"63aebfafa8b59bf5aac97714",
"63aec14da8b59bf5aac97717",
"63aec254a8b59bf5aac9771a"
]
}
]
I don't know if I succeed to explain my issue.
I'm expecting to access to dish objects that belongs to specific restaurant and this my fetch function in the front project I don't know what to put in the URL exactly:
const fetchData = async () => {
try {
const url = ("http://localhost:3001/api/restaurants/getRestaurants/");
const response = fetch(url).then((res) =>
res.json()).then((data) => console.log(data));
return response;
}
catch (error) {
throw error;
}
}
You issue is with your .then(data => console.log(data)). When console.log returns undefined, response becomes a promise that resolves to undefined -
const fetchData = async () => {
try {
const url = ("http://localhost:3001/api/restaurants/getRestaurants/");
const response = fetch(url).then((res) =>
res.json()).then((data) => console.log(data)); // ❌ console.log returns undefined
return response;
}
catch (error) {
throw error;
}
}
To fix it, await the fetch and synchronously console.log after response is received -
const fetchData = async () => {
try {
const url = ("http://localhost:3001/api/restaurants/getRestaurants/");
const response = await fetch(url).then((res) => res.json()) // ✅ await
console.log(response) // ✅
return response;
}
catch (error) {
throw error;
}
}
Make it a reusable function!
const fetchData = async (url) => { // ✅ url as parameter
try {
const response = await fetch(url).then((res) => res.json())
console.log(response)
return response;
}
catch (error) {
throw error;
}
}
fetchData("http://localhost:3001/api/restaurants/getRestaurants/").then(data => ...)
Avoid catch..throw anti-pattern! The try..catch block is basically pointless as it re-throws whatever error occurs. Allow it to bubble up without catching it -
const fetchData = async (url) => {
const response = await fetch(url).then((res) => res.json())
console.log(response)
return response;
}
Remove the console.log side effect! You don't want console output for every fetchData call. Let's write a trace function so we can see the specific data we are interested in -
const fetchData = async (url) => {
const response = await fetch(url).then((res) => res.json())
return response; // ✅ zero side effects
}
const trace = x => {
console.log(x)
return x
}
fetchData(myUrl).then(trace).then(data => ...) // ✅ trace where needed
Avoid async..return..await anti-pattern! This function does the same exact thing as above -
const fetchData = url => // ✅ async not needed
fetch(url).then(res => res.json()) // ✅ await not needed
fetchData(myUrl).then(trace).then(data => ...) // ✅ works the same!
Make fetchData more generic! There are times you may wish to change the request type from GET to POST, send a body, or alter the headers of the request -
const fetchData = (url, options = {}) => // ✅ options parameter
fetch(url, options).then(res => res.json())
fetchData(myUrl).then(data => ...) // ✅ without options
fetchData(myUrl, { method: "POST", body: ... }) // ✅ with options
Rename it! fetchData is ambiguous now. Call it fetchJson or perhaps simply request -
const request = (url, options = {}) => // ✅ appropriate name
fetch(url, options).then(res => res.json())
request(myUrl).then(trace).then(data => ...) // ✅ clean af

Propagate live updates return promise object instead of value

Working on beginner steps toward vue 3 and firestore migration. Stuck on simple.
import { getUsersCount } from "/src/firebase";
setup() {
const usersCount = getUsersCount();
return {
usersCount,
};
},
Why it returns Promise Object, I cant find in manuals.
export const getUsersCount = async () => {
// const querySnap = await getDocs(query(collection(db, "users")));
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
console.log("usersCount33: ", querySnapshot.size);
//unsub();
return querySnapshot.size;
});
}
Nad the last part with template,
<template>
<p>Users Count: {{ usersCount }}</p>
</template>
If you return the value inside a callback, you can not use async await syntax. You should do this:
export const getUsersCount = () => {
return new Promise((resolve, reject) => {
const q = query(collection(db, "users"));
const unsub = onSnapshot(q, (querySnapshot) => {
return resolve(querySnapshot.size)
});
})
}
// You still need to wait getUsersCount when using it
const usersCount = await getUsersCount();

How to use axios to `fetch all()`

I don't understand how to use axios to fetch data from an array of urls. But I can do it with fetch. The following code works perfectly:
const url = 'https://vimeo.com/api/oembed.json?url='
async index(videoUrls = []) {
try {
const response = await Promise.all(
// videoUrls.map(videoUrl => axios.$get(`${url}${encodeURIComponent(videoUrl)}`))
videoUrls.map(videoUrl => fetch(`${url}${encodeURIComponent(videoUrl)}`))
)
const results = await Promise.all(response.map(r => r.json()));
return results;
} catch (e) {
console.error(e)
}
}
When I make a call like index(["https://vimeo.com/216850224", "https://vimeo.com/642263700"]), my console shows an array with all the video meta details vimeo has to give me. This is perfect.
But the moment I comment out the line that uses fetch and use axios, I get a CORS error.
What is the idiomatic way to fetch data from a bunch of urls in axios?
EDIT
I also tried this, but the .all() function doesn't seem to exist
async index(videoUrls = []) {
try {
const response = await axios.all(videoUrls.map(videoUrl => `${url}${encodeURIComponent(videoUrl)}`));
return response;
} catch (e) {
console.error(e)
}
}
You can easily do it like below:
(async function getAll() {
const axiosrequest1 = axios.get('https://jsonplaceholder.typicode.com/posts');
const axiosrequest2 = axios.get('https://jsonplaceholder.typicode.com/posts');
const axiosrequest3 = axios.get('https://jsonplaceholder.typicode.com/posts');
const [res1, res2, res3] = await Promise.all([axiosrequest1, axiosrequest2, axiosrequest3]);
console.log('request1', res1.data);
console.log('request2', res2.data);
console.log('request3', res3.data);
})();
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
The Axios version would be slightly different because it automatically decodes and embeds the response body into the response.data property (no need for res.json())
const baseUrl = "https://vimeo.com/api/oembed.json"
const index = async (videoUrls = []) => {
// create an array of responses and wait for them to resolve
const responses = await Promise.all(
videoUrls.map(url => axios.get(baseUrl, { params: { url } })
)
// extract the `data` properties and return them as an array
return responses.map(({ data }) => data)
}
Exactly when you extract response.data is totally up to you. It could also look like this
const index = (videoUrls = []) => Promise.all(
videoUrls.map(async (url) => (
await axios.get(baseUrl, { params: { url } })
).data)
)
FYI, your fetch() version could be a little cleaner too...
const baseUrl = "https://vimeo.com/api/oembed.json"
const index = (videoUrls = []) => Promise.all(
videoUrls.map(async (url) => {
const params = new URLSearchParams({ url })
const res = await fetch(`${baseUrl}?${params}`)
if (!res.ok) { // check for bad response
throw new Error(`${res.status}: ${await res.text()}`)
}
return res.json()
})
)

Nexjs + SWR: API resolved without sending a response for /api/projects/<slug>, this may result in stalled requests

Since on first render I was not able to get the router.query I am passing the params from getServerSideProps as follows:
export async function getServerSideProps(context) {
return {
props: { params: context.params },
};
}
Then in the function am trying to do the API call but am getting the API stalled error
API resolved without sending a response for
/api/projects/nichole_robel23, this may result in stalled requests.
This is my code:
export default function Project({ params }) {
const { slug } = params;
let [projectData, setProjectData] = useState([]);
let [loading, setLoading] = useState(true);
const { data } = useSWR('http://localhost:3000/api/projects/' + slug);
useEffect(() => {
if (data) {
setProjectData(data.data.project);
setLoading(false);
}
}, [data]);
......
I have global SWRCofig as follows
<SWRConfig value={{ fetcher: (url) => axios(url).then(r => r.data) }}>
<Layout>
<Component {...pageProps} />
</Layout>
</SWRConfig>
Any way to solve the problem?
You are missing your fetcher–the function that accepts the key of SWR and returns the data, so the API is not being called.
You are also not returning a response correctly from the API–this is most likely a case of not waiting for a promise/async to be fulfilled correctly.
CLIENT
const fetcher = (...args) => fetch(...args).then((res) => res.json());
export default function Home({ params }) {
const { slug } = params;
const [projectData, setProjectData] = useState([]);
const [loading, setLoading] = useState(true);
const { data } = useSWR(`http://localhost:3000/api/projects/${slug}`, fetcher);
useEffect(() => {
if (data) {
setProjectData(data);
setLoading(false);
}
}, [data]);
API
const getData = () => {
return new Promise((resolve, reject) => {
// simulate delay
setTimeout(() => {
return resolve([{ name: 'luke' }, { name: 'darth' }]);
}, 2000);
});
}
export default async (req, res) => {
// below will result in: API resolved without sending a response for /api/projects/vader, this may result in stalled requests
// getData()
// .then((data) => {
// res.status(200).json(data);
// });
// better
const data = await getData();
res.status(200).json(data);
}

Why resolving an async promise with a .map() function doesn't work for GET with parameters?

I am not sure how to express my question correctly.
Basically resolving an async promise with a .map() function works for simple get functions while it doesn't work for get functions with parameter.
Basically, in this case, router.get('/' ... the following works:
import axios from 'axios'
const url = 'http://localhost:3000/api/library/'
class libraryService {
// Get stories
static getStories () {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.get(url)
const data = res.data
resolve(
data.map(story => ({
...story
}))
)
} catch (err) {
reject(err)
}
})
}
export default libraryService
While in this case, router.get('/:story_name' ..., this variation doesn't work:
class readService {
// Get story to read
static getStoryToRead (storyName) {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.get(url + storyName)
const data = res.data
resolve(
data.map(selectedStory => ({
...selectedStory
}))
...
In here I get an error: 'data.map is not a function'.
Changing to data.products.map() will return an error 'Cannot read property 'map' of undefined'.
However resolving data without .map() function will work on all cases:
try {
const res = await axios.get(...)
const data = res.data
resolve(
data
)
...
Why this is happening and is it correct to just use resolve(data)?
You seem to be asking for a single story in the case that doesn't work. So instead of an array of stories, presuambly you're getting just the one story that you asked for. There's no reason to try to use map.
Minimal changes (but keep reading):
// Minimal changes, but keep reading...
static getStoryToRead (storyName) {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.get(url + storyName);
resolve(res.data);
} catch (err) {
reject(err);
}
});
}
But, both of those functions demonstrate the Promise creation antipattern. You already have a promise, work with it. In this case, you'd probably do that by making the functions async:
static async getStories () {
const {data} = await axios.get(url);
return data.map(story => ({ // Why copy the story objects?
...story
}));
}
static async getStoryToRead (storyName) {
const {data} = await axios.get(url + storyName));
return data;
}
Or with non-async functions:
static getStories () {
return axios.get(url)
.then(({data}) => data.map(story => ({...story}))); // Why copy the story objects?
}
static getStoryToRead (storyName) {
return axios.get(url + storyName))
.then(({data}) => data);
}