How to fetch the next set of results from a paginated API? - javascript

I'm fetching data from an API that is paginated server-side. I have limited the number of results to 5 (rows=5). For the first set of data, a global variable pageNumber has been declared to 1, and eventListeners for the Previous/Next buttons have been added. Now I don't know how to get the next set of results. They can be fetched by changing the pageNumber to 2 but I don't know how to access the URL from const endpoint where I would change the pageNumber parameters to get previous and/or next results. Any idea how to do that?
// First set of fetched data starts with page 1
let pageNumber = 1;
// 1. Define endpoint, fetch response and return data promise
const search = async (term) => {
const key = 'aroplosuitin';
const endpoint = `https://api.europeana.eu/record/v2/search.json`,
query = `?wskey=${key}&query=${term}&start=${pageNumber}&rows=5&profile=rich'`;
const response = await fetch(endpoint + query);
// Check response status:
if (response.status !== 200) {
throw new Error('Cannot fetch data. Response status is not 200.');
}
const data = await response.json();
return data;
};
// 2. Call search and return data promise
const searchEuropeana = async (term) => {
const data = await search(term);
return data;
};
// 3. Grab the input and invoke callback to update the UI
const searchForm = document.querySelector('#search-form');
searchForm.addEventListener('submit', (e) => {
e.preventDefault();
// grab user input
const userInput = searchForm.search.value.trim();
// reset form on submit
searchForm.reset();
// For errors
const errorOutput = document.querySelector('.error');
// Invoke searchEuropeana
searchEuropeana(userInput)
.then((data) => {
updateUI(data);
console.log(data);
})
.catch((error) => {
console.log('An error occured:', error),
(errorOutput.innerText = 'Check your spelling or network.');
});
});
// 4. Update the UI with HTML template
const updateUI = (data) => {
console.log(data);
};
// 5. Previous / Next results
const previousBtn = document.querySelector('#previousBtn'),
nextBtn = document.querySelector('#nextBtn');
previousBtn.addEventListener('click', () => {
if (pageNumber > 1) {
pageNumber--;
} else {
return;
}
console.log(pageNumber);
searchEuropeana();
});
nextBtn.addEventListener('click', () => {
pageNumber++;
console.log(pageNumber);
searchEuropeana();
});
<main id="main">
<h2>(Be)Heading</h2>
<br>
<section id="search">
<form id="search-form">
<div class="form-group search-group">
<input type="text" name="search" id="search" required>
<button id="searchButton" class="btn" type="submit">Search</button>
</div>
</form>
</section>
<br>
<section id="output">
<!-- Error messages -->
<div class="error"></div>
</section>
<button id="previousBtn" class="btn" type="submit">Previous</button>
<button id="nextBtn" class="btn" type="submit">Next</button>
</main>

// First set of fetched data starts with page 1
let pageNumber = 1;
let term = '';
// 1. Define endpoint, fetch response and return data promise
const search = async () => {
const key = 'aroplosuitin';
const endpoint = `https://api.europeana.eu/record/v2/search.json`,
query = `?wskey=${key}&query=${term}&start=${pageNumber}&rows=5&profile=rich'`;
const response = await fetch(endpoint + query);
// Check response status:
if (response.status !== 200) {
throw new Error('Cannot fetch data. Response status is not 200.');
}
const data = await response.json();
return data;
};
// 2. Call search and return data promise
const searchEuropeana = async () => {
const data = await search();
return data;
};
// 3. Grab the input and invoke callback to update the UI
const searchForm = document.querySelector('#search-form');
searchForm.addEventListener('submit', (e) => {
e.preventDefault();
// grab user input
term = searchForm.search.value.trim();
// reset form on submit
searchForm.reset();
// For errors
const errorOutput = document.querySelector('.error');
// Invoke searchEuropeana
searchEuropeana()
.then((data) => {
updateUI(data);
console.log(data);
})
.catch((error) => {
console.log('An error occured:', error),
(errorOutput.innerText = 'Check your spelling or network.');
});
});
// 4. Update the UI with HTML template
const updateUI = (data) => {
console.log(data);
};
// 5. Previous / Next results
const previousBtn = document.querySelector('#previousBtn'),
nextBtn = document.querySelector('#nextBtn');
previousBtn.addEventListener('click', () => {
if (pageNumber > 1) {
pageNumber--;
} else {
return;
}
console.log(pageNumber);
searchEuropeana();
});
nextBtn.addEventListener('click', () => {
pageNumber++;
console.log(pageNumber);
searchEuropeana();
});
EDIT:
Take a look at a more readable approach
// First set of fetched data starts with page 1
const searchFormEl = document.querySelector("#search-form");
const errorEl = document.querySelector(".query");
const nextBtn = document.querySelector("#nextBtn");
const prevBtn = document.querySelector("#previousBtn");
const searchEl = document.querySelector("#search");
let pageNumber = 1;
const getApiUrl = () => {
const key = "aroplosuitin";
const endPoint = `https://api.europeana.eu/record/v2/search.json`;
const query = `?wskey=${key}&query=${searchEl.value.trim()}&start=${pageNumber}&rows=5&profile=rich'`;
return `${endPoint}${query}`;
};
// 1. Define endpoint, fetch response and return data promise
const search = async () => {
const response = await fetch(getApiUrl());
// Check response status:
if (response.status !== 200) {
throw new Error("Cannot fetch data. Response status is not 200.");
}
const data = await response.json();
return data;
};
// 2. Call search and return data promise
const searchEuropeana = async () => await search();
// 3. Grab the input and invoke callback to update the UI
searchFormEl.addEventListener("submit", (e) => {
e.preventDefault();
// Invoke searchEuropeana
searchEuropeana()
.then((data) => {
updateUI(data);
console.log(data);
searchFormEl.reset();
})
.catch((error) => {
console.log("An error occured:", error);
errorEl.innerText = "Check your spelling or network.";
});
});
// 4. Update the UI with HTML template
const updateUI = (data) => {
console.log(data);
};
prevBtn.addEventListener("click", () => {
pageNumber = pageNumber > 1 ? pageNumber - 1 : pageNumber;
searchEuropeana().then(updateUI);
});
nextBtn.addEventListener("click", () => {
pageNumber++;
searchEuropeana().then(updateUI);
});

Related

How to get API data from node js to display on React

I'm learning react and node js and I'm making a macro calculator website and basically I get data (calories, macro ratio, etc..) from the user on client side then using those data I make a get request to edamam API server to get (foodID, uri, unit) and post those data again to get macros for each food. Then I calculated data. (It's working fine up to this point on the backend). And I want send this data to back to frontend to display and it's not working here. I'm using axios for the requests. I'm also not too sure it's right way to make API calls. Any help would be appreciated!! Thank you!
Send data to backend from React
async function postData(e){
e.preventDefault();
try{
await axios.post("http://localhost:4000/getData", {formData})
}
catch(error){
console.log(error.response.data);
}
}
Node.js to make API calls and process data
app.post("/getData", (req, res) =>{
// data from React
const targetKcal = req.body.formData.calories;
const proteinRatio = req.body.formData.proteinRatio;
const fatRatio = req.body.formData.fatRatio;
const carbRatio = req.body.formData.carbRatio;
const proteinSource = req.body.formData.proteinSource;
const fatSource = req.body.formData.fatSource;
const carbSource = req.body.formData.carbSource;
const getURL = "https://api.edamam.com/api/food-database/v2/parser?";
const postURL = "https://api.edamam.com/api/food-database/v2/nutrients?";
//GET Request to parse and get uri and foodID to post
try{
Promise.all([
axios.get(getURL, {params :{"ingr" : proteinSource}}),
axios.get(getURL, {params :{"ingr" : fatSource}}),
axios.get(getURL, {params :{"ingr" : carbSource}}),
]).then(axios.spread((proteinData, fatData, carbData) => {
try{
//post data to get macro info for each macros
Promise.all([
axios.post(postURL, {"ingredients" :[{"quantity":1, "measureURI": proteinData.data.hints[0].measures.filter(obj => obj["label"] === "Gram")[0].uri,"foodId":proteinData.data.parsed[0].food.foodId}]}),
axios.post(postURL, {"ingredients" :[{"quantity":1, "measureURI": fatData.data.hints[0].measures.filter(obj => obj["label"] === "Gram")[0].uri,"foodId":fatData.data.parsed[0].food.foodId}]}),
axios.post(postURL, {"ingredients" :[{"quantity":1, "measureURI": carbData.data.hints[0].measures.filter(obj => obj["label"] === "Gram")[0].uri,"foodId":carbData.data.parsed[0].food.foodId}]})
]).then(axios.spread((data1, data2, data3) => {
let proteinKcal = data1.data.totalNutrients.ENERC_KCAL.quantity;
let protein = data1.data.totalNutrients.PROCNT.quantity;
let proteinFat = data1.data.totalNutrients.FAT.quantity;
let proteinCarb = data1.data.totalNutrients.CHOCDF.quantity;
let fatKcal = data2.data.totalNutrients.ENERC_KCAL.quantity;
let fatProtein = data2.data.totalNutrients.PROCNT.quantity;
let fat = data2.data.totalNutrients.FAT.quantity;
let fatCarb = data2.data.totalNutrients.CHOCDF.quantity;
let carbKcal = data3.data.totalNutrients.ENERC_KCAL.quantity;
let carbProtein = data3.data.totalNutrients.PROCNT.quantity;
let carbFat = data3.data.totalNutrients.FAT.quantity;
let carb = data3.data.totalNutrients.CHOCDF.quantity;
//Calculate each macros for target calories
const proteinTargetGram = (targetKcal * (proteinRatio / 100))/proteinKcal;
const fatTargetGram = (targetKcal * (fatRatio / 100))/fatKcal;
const carbTargetGram = (targetKcal * (carbRatio / 100))/carbKcal;
proteinKcal *= proteinTargetGram;
protein *= proteinTargetGram;
proteinFat *= proteinTargetGram;
proteinCarb *= proteinTargetGram;
fatKcal *= fatTargetGram;
fatProtein *= proteinTargetGram;
fat *= fatTargetGram;
fatCarb *= proteinTargetGram;
carbKcal *=carbTargetGram;
carbProtein *= proteinTargetGram;
carbFat *= proteinTargetGram;
carb *= carbTargetGram;
const totalKcal = (proteinKcal + fatKcal + carbKcal).toFixed(0);
const totalProtein = (protein + fatProtein + carbProtein).toFixed(0);
const totalFat = (proteinFat + fat + carbFat).toFixed(0);
const totalCarb = (proteinCarb + fatCarb + carb).toFixed(0);
const data = {
"totalKcal": totalKcal,
"totalProtein": totalProtein,
"totalFat": totalFat,
"totalCarb": totalCarb,
"proteinTargetGram": proteinTargetGram,
"fatTargetGram": fatTargetGram,
"carbTargetGram":carbTargetGram
};
//send back the data
res.json(data);
}))
}catch(err) { console.log(err); }
}));
}
catch (err) { console.error(err); }
});
Use the data to display on React
function Result() {
const [data, setData] = useState([]);
useEffect(()=>{
const getData = async ()=> {
const response = await axios.get('/getData');
setData(response.data);
};
getData();
});
return (
<div>
<h1>{data.map(item => item)}</h1>
</div>
)
}
export default Result
Error message
-----------------------Edit-------------------------------------------
Instead of res.json(data) I added below
axios.post('/getData', data)
.then(res => console.log(res.json))
.catch(err => console.log(err.json));
display on react
function Result() {
const [data, setData] = useState([]);
useEffect(()=>{
const getData = async ()=> {
const response = await axios.get('http://localhost:4000/getData');
setData(response.data);
};
getData();
});
return (
<div>
<h1>{Object.keys(data).map(key => data[key])}</h1>
</div>
)
}
I still get an error
Your error is generated because you are asking to a GET method that doesn't exist on backend, that's why you see 404 there.
You actually have a POST declared (getData), you should request to the POST method by passing the values on the body. something like this:
axios.post('/getData', {
// pass the formData here
formData:{
// calories: ...,
// ...
}
})
.then(function (response) {
// update state
})
.catch(function (error) {
// handle error
});
Axios is fine, if you don't want to use an external package you can use fetch. You can find the documentation here.
For the render: you have to do something different, since you are receiving an object you should map on keys, change this:
<h1>{data.map(item => item)}</h1>
to something like this:
<h1>{Object.keys(data).map(key => key + ": " + data[key])}</h1>

How wait for data(Array) from server and then push something into it in js?

I have problem with my code, problem is i get array from server with async function (getData()) and then i want push one object into it but it doesn't work and have error like this :
sandbox.js:61 Uncaught TypeError: Cannot read properties of undefined (reading 'push')
at submitData (sandbox.js:61)
at handleInputs (sandbox.js:44)
at HTMLButtonElement.<anonymous> (sandbox.js:35)
and the code is here :
var dataBase;
const getData = async() => {
const url = 'http://localhost:8080/readData';
const res = await fetch(url);
const data = awair res.json();
dataBase = data;
}
const handleInputs = () => {
if (userName.value === "" && password.value === "" && repeatPassword.value === "" && checkTerms.checked) {
alert('Please fill the input');
} else {
if (password.value === repeatPassword.value) {
getData();
submitData();
renderUser();
form.reset();
} else {
alert('Password does not match with repeat password input')
}
}
}
const submitData = () => {
let userObj = {
userName: userName.value,
password: password.value,
id: countId++
}
dataBase.push(userObj); // problem here
sendData();
}
and how can i fix it ?
Here, I have removed the functions not declared here for now. You can add it later.
You are getting this error because you have not initialized database with any value, here an array
I am returning Promise to wait till the user is fetched.
Note: You were having the same variable dataBase for saving newly fetched data. I have created a new data variable for saving newly fetched data and database variable for saving it for further use.
let newData;
let dataBase =[];
const getData = () => {
return new Promise(async(resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/users/1';
const res = await fetch(url);
const data = await res.json();
console.log(data);
newData = data;
resolve();
})
}
const handleInputs = async () => {
await getData();
submitData();
console.log("database", dataBase);
}
const submitData = () => {
let userObj = {
userName: newData.username,
password: newData.email,
id: newData.id
}
//it is showing undefined as you have not initialized database with any value, here an array
dataBase.push(userObj);
}
handleInputs();

UI update with GET method

I'm working on a project to get the api from openweathermap using node js & express & then update the UI.
I'm trying to update the UI of the page with the GET data, but it does not work. it prints undefined instead of the required values.
it works and gets the api from openweathermap on the terminal & console.
any help would be appreciated!
/* Global Variables */
const date = document.getElementById('date').value;
const temp = document.getElementById('temp').value;
// Create a new date instance dynamically with JS
let d = new Date();
let newDate = d.getMonth()+'.'+ d.getDate()+'.'+ d.getFullYear();
//baseURL & apiKey
const baseURL = `http://api.openweathermap.org/data/2.5/weather?zip=`;
const apiKey = `&appid=...`;
//event listener when user clicks generate button
const button = document.getElementById('generate');
button.addEventListener('click', performAction);
//event listener function
function performAction(event) {
const zip = document.getElementById('zip').value;
const feelings = document.getElementById('feelings').value;
getData(baseURL, zip, apiKey)
.then(function (data) {
console.log(data);
postData('/add', {date: newDate, temp: data.main.temp, feelings: feelings});
updateUI();
})
};
//function to fetch api data
const getData = async (baseURL, zip, apiKey) => {
const res = await fetch(baseURL+zip+apiKey)
try {
const data = await res.json();
return data;
console.log(data);
}catch(error) {
console.log("error", error);
}
}
// user input post data function
const postData = async (url = '', data = {}) => {
const response = await fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
});
try {
const newData = await response.json();
}catch (error) {
console.log("error", error);
}
};
//updating UI
const updateUI = async () => {
const request = await fetch('/all');
try{
const allData = await request.json();
document.getElementById('date').innerHTML = allData.date;
document.getElementById('temp').innerHTML = allData.temp;
document.getElementById('content').innerHTML = allData.content;
}catch(error){
console.log("error", error);
}
}

Nodejs asynchronous function print data before execution fished

I am using following NodeJS module for getting onvif device in the network https://github.com/futomi/node-onvif, and which works fine.
But using below code the list of device found is always empty. I checked the getDeviceData function and which is getting the device and print data.
But using below code the line console.log(JSON.stringify(list)); execute before all scan process completed. How can I fix it.
async function getDeviceData(info){
var device = new onvif.OnvifDevice({
xaddr: info.xaddrs[0],
user : 'admin',
pass : '123456'
});
await device.init();
var dev_info = device.getInformation();
var rtsp_url = device.getUdpStreamUrl();
var data = {"Manufacturer":dev_info.Manufacturer,"Model":dev_info.Model};
console.log(data); // this print last
return data;
}
const onvif = require('node-onvif');
onvif.startProbe().then((device_info_list) => {
var list = [];
device_info_list.forEach((info) => {
var data = getDeviceData(info)
list.push(data);
});
console.log(JSON.stringify(list)); // this print first
}).catch((error) => {
console.error(error);
});
Here is what you want:
You need to use await to wait the promise to resolve with the data.
onvif.startProbe().then(async (device_info_list) => {
var list = [];
await Promise.all(device_info_list.map(async(info) => {
var data = await getDeviceData(info)
list.push(data);
}));
console.log(JSON.stringify(list)); // this print first
}).catch((error) => {
console.error(error);
});
The data const in the first function returns a promise so would have yo await that. So this should work:
async function getDeviceData(info) {
const device = new onvif.OnvifDevice({
xaddr: info.xaddrs[0],
user: 'admin',
pass: '123456',
});
await device.init();
const dev_info = device.getInformation();
const rtsp_url = device.getUdpStreamUrl();
const data = { Manufacturer: dev_info.Manufacturer, Model: dev_info.Model };
await Promise.resolve(data);
console.log(data); // this print last
return data;
}
onvif
.startProbe()
.then(device_info_list => {
const list = [];
device_info_list.forEach(async info => {
const data = await getDeviceData(info);
await Promise.resolve(list.push(data));
});
console.log(JSON.stringify(list)); // this print first
})
.catch(error => {
console.error(error);
});

TypeError: Failed to fetch - Problem with Javascript Asyn

I just start learning Javascript. I am currently learning asynchronous js. I want to build a Weather Application with AccuWeather API. But its keep throwing error in the console and it not working
Here is the error
TypeError: Failed to fetch
In my directory. I have
Index.html
...
<link rel="stylesheet" href="style.css">
...
<form class="change-location my-4 text-center text-muted">
<label for="city">Enter a location for weather information</label>
<input type="text" name="city" class="form-control p-4">
</form>
...
<script src="scripts/forecast.js"></script>
<script src="scripts/app.js"></script>
app.js
//Select the form
const cityForm = document.querySelector('form');
//get city details & weather
const updateCity = async (city) => {
const cityDets = await getCity(city);
const weather = await getWeather(cityDets.key);
//returns city and weather response
return {
cityDets: cityDets,
weather: weather
};
};
//prevent default action
cityForm.addEventListener('submit', e => {
e.preventDefault
//trim any whitespace & get city value
//cityForm.city.value = selection + input name + input value
const city = cityForm.city.value.trim();
//remove the previous entry
cityForm.reset();
//update the UI withcity info
updateCity(city)
.then(data => console.log(data))
.catch(err => console.log(err));
});
In my app.js
const key = '*****************';
const getWeather = async (id) => {
const base = 'http://dataservice.accuweather.com/currentconditions/v1/';
const query = `${id}?apikey=${key}`;
const response = await fetch (base + query);
const data = await response.json();
return data[0];
}
//get city information
const getCity = async (city) => {
//base, apikey, cityname -
const base = 'http://dataservice.accuweather.com/locations/v1/cities/search';
const query = `?apikey=${key}&q=${city}`;
const response = await fetch(base + query);
const data = await response.json();
return data[0];
};
I don't know what I am doing wrong.
try catching your error after the fetch call:
const url = 'https://weatherapi/basepath'+key; //or whatever this is
fetch(url)
.then(res => ...do stuff)
.catch(err => console.log('ERROR', error)); //here

Categories

Resources