Shopify REST API Pagination using Node.js and Express - javascript

I'm facing an issue, using Product resource on Shopify REST Api : I need to display many products on a Node.js Express app, I've left the default limit at 50 and when I want to fetch the next page of 50 products when I click on a next or previous button (I use the nextPageUrl/prevPageUrl from the response headers) I get a 401 error if the request is made from the client-side because of CORS error
Then I tried to make the request on server-side, I've passed the link from client to server when hitting the next button for example but it still does not work
The documentation is not clear at all about the paginated request and nothing that i've done from the documentation now is correct, it just says "Make a GET request to the link headers" and voila
Anyone have done this before ?
Code below
protectedRouter.get('/inventory', async (req, res) => {
try {
const session = await Shopify.Utils.loadCurrentSession(req, res);
const client = new Shopify.Clients.Rest(session.shop, session.accessToken)
const result = await client.get({
path: 'products',
})
res.render('inventory', {
products: result,
})
} catch (error) {
throw error;
}
});
script(src="/scripts/pagination.js")
div.View
h3.title.my-4 Etat des stocks
div.row
div.col-6
span(id='previousLink') #{products.pageInfo.prevPageUrl ? products.pageInfo.prevPageUrl : '' }
button.btn.btn-outline-dark.ml-4(id="previous_btn")
i(class="bi bi-arrow-left-circle-fill") Précédent
div.col-6
span(id='nextLink') #{products.pageInfo.nextPageUrl ? products.pageInfo.nextPageUrl : '' }
a.btn.btn-outline-dark.float-right.mr-4(id="next_btn") Suivant
i(class="fa-solid fa-circle-arrow-right")
window.addEventListener('DOMContentLoaded', () => {
console.log('dom content loaded')
document.getElementById('next_btn').onclick = function (e) {
console.log('next button clicked')
const nextLink = document.getElementById('nextLink').innerHTML;
fetch(nextLink).then(response => {
console.log(response);
}).catch(error => {
console.log(error)
})
console.log(nextLink)
}
});

You're doing it wrong. If you want to display Shopify products in your own App, you use the StorefrontAPI calls. With a StorefrontAPI token, you get products, and can display them. Trying to use Admin API calls is never going to work properly. Switch to StorefrontAPI and all your problems go away.

Related

Is it good practice to access req.query in a PUT request?

I'm building a website with an API using NEXTjs. For a single element, I use the dynamic api route provided by NEXTjs and I'm currently using that route both for getting an element and updating element.
In both the GET and PUT request, I use the req.query.fetchId to get or update the element.
However, I see req.query mostly used for GET requests and in POST/PUT request it's usually req.body being used.
It seems to work, but I'm wondering if I should?
This is the URL for the request: api/items/[fetchId]
And this is my code for the PUT request so far:
if (req.method==="PUT") {
try {
const { db } = await connectToDatabase();
const videoGamesCollection = db.collection("videogames");
const result = await videoGamesCollection
.updateOne({ _id: ObjectId(req.query.fetchId) }, {$inc: {}})
res.status(200).json({ message: "success", result: result });
} catch (error) {
res.status(error.code ?? 502).send({
message: error.message ?? "Something went wrong.",
});
}
}

not able to send request to express server using axios

I am building a chat application like whatsapp, & implementing the feature - when user clicks on any person's name, his chats appears, but can't able to send request to server when user clicks
Source code
There is div, when user will click on it, it will fetch data from server (onclick event handler) in Sidebar.js file -
{friends.map((e) => (
<div
onClick={getChatDetails}
key={e.friendName}
className='sidebar_chat_info'>
<Avatar />
<div>
<h2>{e.friendName}</h2>
<p>{getLastMessage()}</p>
</div>
</div>
))}
this is getChatDetails function in sidebar.js file
const getChatDetails = (e) => {
//console.log(e.target.textContent);
const Myfriend = e.target.textContent;
axios
.post('http://localhost:2000/message/get', { friend: Myfriend })
.then((response) => {
console.log(response);
})
.catch((error) => console.log(error));
};
At the server side , this is route in index.js file
Server is running on port 2000
app.post('/message/get', isloggedIn, async (req, res) => {
console.log('REQUESTED!');
try {
const conversation = await req.user.MyConversation.find(
(element) => element.friendName == req.body.friend
);
const messages = await conversationModel.findById(conversation.chats);
res.send(messages);
//await MessageModel.remove({})
} catch (error) {
res.status(500).send(error);
}
});
This is error on browser console , when I am clicking on div
But when I am sending request through postman, I am getting response
When I am sending request in other files (login.js), it's working there, don't know why it is not working only Sidebar.js file
The issue that you're having is that e in getChatDetails is undefined. The reason for this is is onclick does not pass an event object. In order to pass an event object to your sidebar function, you need to attach an event listener to it, which is a bit better than using onclick in most cases anyways (imo). Something like this:
const sidebar = document.getElementsByClassName('sidebar_chat_info')
for (let i = 0; i < sidebar.length; i++) {
sidebar[i].addEventListener('click', handleClick = e => {
//console.log(e.target.textContent);
const Myfriend = e.target.textContent;
axios
.post('http://localhost:2000/message/get', { friend: Myfriend })
.then((response) => {
console.log(response);
})
.catch((error) => console.log(error));
})
The middleware "isLoggedIn" causing issue. The problem was in my authentication part, when the user has been logged in then only he will see home page
index.js file at line 113
I added console.log and found that "NOT LOGGED IN " is displayed
function isloggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
console.log('NOT LOGGED IN !');
res.status(500).send('DENIED PERMISSION!');
}
}
I think it is happening because after logging in , I am redirecting to home page from
Login.js at line 59
history.push('/', { user: response.data });
const submitForm = async (e) => {
e.preventDefault();
axios
.post('http://localhost:2000/login', {
username: username,
password: password,
})
.then((response) => {
history.push('/', { user: response.data });
})
.catch((error) => setIsError(true));
//console.log(user.data); //user.data contains the details
//CALLING THE HOME PAGE AFTER SIGNUP & SENDING DETAILS OF CURRENT USER THERE !
//history.push('/', { user: user.data });
};
Maybe the request will be authenticated only from Login.js file, but I can't make other request from this file like getting chats details, sending message etc. I will have to go to home page . That's why I am redirecting to home page after logging in
On home page my request is not authenticated.
In postman all routes are working as I am not switching pages.
Login and logout routes are working as they are not taking in account "isLoggedIn"
Please suggest how to work with routes that needs authentication, like send message, gettingchats details?
PS - My request is even not authenticated from Login.js. After logging in, this time I didn't redirect to home page. I made request to route that needs authentication after logging in , it's still showing "NOT LOGGED IN" on server

Express Server - cannot POST but can GET, mongoDB problem or backend server problem?

I recently deployed my first project, a MERN stack to heroku. However after deployment, I have been met with issues that weren't present in development. A brief explanation of what my web does is that it takes data from mongoDB and allow user to add multiple filters to search through them. It also have the function that allow you to create new data and edit old data. The problem I have is that all function with POST is not working, they would fire but it would have the error of "net::ERR_CONNECTION_REFUSED" and "EditInfo.jsx:58 Error: Network Error at e.exports (createError.js:16)"
at XMLHttpRequest.p.onerror (xhr.js:84)in the network dev tool. However GET works just fine, which means my dynamically generated table would work, but I cannot make new or edit previous data (just as a side note, I cannot generate data for edit although i was able to generate the same data for previously metioned table. I think this is because I'm asking for the data thorough post and for the table through get).I think the issue isn't from MongoDB since GET is working, so my guess would be I need to do some config to allow POST to my server. I'll post some of the function that works and some that doesn't. Any help or lead would be greatly appreciated, Thanks.
Here is one that works:
client side
useEffect(() => {
fetch("/data").then(res => {
if(res.ok) {
return res.json();
} else {
console.error("Cannot asscess data")
}
})
.then(jsonRes => setData(jsonRes))
setError(0)
setShowError(false)
// eslint-disable-next-line react-hooks/exhaustive-deps
},[resetData])
Here is the server
router.route("/data").get((req,res) => {
Disease.find({}, async(err, foundDisease) => {
if(err) {
console.error(err)
} else {
foundDisease.sort(function(a, b){
var nameA=a.diseaseName.toLowerCase(), nameB=b.diseaseName.toLowerCase();
if (nameA < nameB) //sort string ascending
return -1;
if (nameA > nameB)
return 1;
return 0;
});
res.json(foundDisease);}
})
})
Here is one that doens't work:
Here is the client (I use post to get the data because I need to send the id of what info I need)
useEffect(() => {
const idInfo = {id};
axios.post('http://localhost:3001/info', idInfo)
.then(function(res){
setInput({
diseaseName: res.data[0].diseaseName,
species: res.data[0].species,
vector: res.data[0].vector,
vectorName: res.data[0].vectorName,
agent: res.data[0].agent,
agentName: res.data[0].agentName,
symptoms: res.data[0].symptoms,
diagnosis: res.data[0].diagnosis,
treatment: res.data[0].treatment,
prognosis: res.data[0].prognosis,
notes: res.data[0].notes
})
res=null
})
.catch(err => console.error(err))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
Here is the server
router.route("/info").post((req, res) => {
console.log(req.body)
const idInfo = req.body.id;
console.log(idInfo);
current_id = idInfo;
Disease.find({_id: current_id})
.then(foundId => res.json(foundId))
.catch(err => console.error(err));
})
axios.post('localhost:3001/info', idInfo)
You're posting to localhost instead of to the actual deployed server. You should either change this into an environment variable or just put ur heroku address there

How to display 404 page if a back-end GET request to an API fails because user doesn't exists? Separated front-end and back-end

I have an application that uses JavaScript with Vue.js for the front-end and PHP with Laravel for the back-end.
Right now, when I make a GET request from my front-end to my back-end on URL /getSummoner/{summonerName}, I make another GET request from my back-end to a third party API in order to get the details for a user with a certain summoner name like this:
public function getSummoner($summonerName){
$summoner = Summoner::where('summoner_name', $summonerName)->first();
if ($summoner === null) {
$apiKey = env("RIOT_API_KEY");
$region = env("EUW");
$getSummonerInfo = file_get_contents($region . "/lol/summoner/v4/summoners/by-name/" . $summonerName . "?api_key=" . $apiKey);
$summonerInfo = json_decode($getSummonerInfo);
$summoner = new Summoner();
$summoner->summoner_name = $summonerName;
$summoner->summoner_info = json_encode($summonerInfo);
$summoner->save();
} else {
$summonerInfo = json_decode($summoner->summoner_info);
}
return response()->json([
'summonerInfo' => $summonerInfo,
], 201);
}
And then I return a JSON response to my front-end with the summoner info. This all works fine and dandy as long as a user with that summoner name exists. If he doesn't exists, the GET request fails so the rest of my function fails and in return I get an error on my front-end.
So I am wondering what am I supposed to do to get a 404 page on the front-end if my back-end GET request doesn't go through? Both on the front and back-end. I assume I need to return some sort of response from the back-end and then based on that response do something on the front-end?
Here's my front-end:
<template>
<div>{{ summonerInfo }}</div>
</template>
<script>
import axios from 'axios'
import router from '../router'
export default {
data(){
return {
summoner: this.$route.params.summonerName,
summonerInfo: '',
}
},
methods: {
user(action){
let trimmedSummoner = this.summoner.replace(/\s+/g, '');
axios.get('/' + action + 'Summoner/' + trimmedSummoner)
.then((response) => {
this.summonerInfo = response.data.summonerInfo
})
.catch(function (error) {
console.log(error);
})
}
},
watch:{
$route (to, from){
this.summoner = this.$route.params.summonerName
this.user('get')
}
},
mounted(){
this.user('get')
}
}
</script>
One poor mans way of doing this would be to wrap your request in a try / catch. This way, when you request fails, you have the opportunity to catch it and redirect. Downside to this method is that it doesn't give you any info on what the status code is (4xx vs 5xx, etc...).
However, a proper solution would be to use Http Interceptors to handle this.
How can you use axios interceptors?
Here is another example using try / catch approach:
https://gist.github.com/fgilio/230ccd514e9381fafa51608fcf137253
They've also got quite a few examples on this within their GitHub Docs:
https://github.com/axios/axios
Interceptor Example:
axios.interceptors.response.use((response) => {
if(response.status === 401) {
alert("You are not authorized");
}
return response;
}, (error) => {
if (error.response && error.response.data) {
return Promise.reject(error.response.data);
}
return Promise.reject(error.message);
});

Firebase response depending on Firestore Query does not work

Depending on whether there is an entry in Cloud Firestore with the correct DocumentId. However, this does not work because my function sends the status 200 before even finishing the query. So how can I get that working?
Here is my code:
access = false;
admin.firebase().collection("tuere").doc(door).collection("eintritt").get().then((snapshot) => {
snapshot.forEach((doc) => {
if(doc.id === uid){
access = true;
console.log("May open door " + uid);
}
});
}).catch((err) => {
console.log(err);
});
res.status(200).send(access);
When I open the Tab in Chrome and let it load "false" appears, but when I wait like 15 Seconds "May open door (uid)" appears in the Logs.
How can I solve this problem and how can i get my function to run faster?
You should send the HTTP response when the promise resolves, so within the then of the query promise: like that:
access = false;
admin.firebase().collection("tuere").doc(door).collection("eintritt").get()
.then((snapshot) => {
snapshot.forEach((doc) => {
if(doc.id === uid){
access = true;
console.log("May open door " + uid);
}
});
res.status(200).send(access);
}).catch((err) => {
console.log(err);
res.status(500).send(err);
});
Also, you should send an HTTP response in case of error, this is why I added res.status(500).send(err); in the catch
I would suggest you look this video from Doug Stevenson: https://www.youtube.com/watch?v=7IkUgCLr5oA
Also there is a point which surprises me: shouln't you use
admin.firestore().collection("tuere").doc(door)....
instead of
admin.firebase().collection("tuere").doc(door)
I have to look in the reference, but I have the feeling that admin.firebase() does not exist.

Categories

Resources