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

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.",
});
}
}

Related

Shopify REST API Pagination using Node.js and Express

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.

How to use the GET and POST method in the same endpoint using nodejs / express

Problem
Hello,
I would like to know how I can create an Endpoint that first uses the POST method to login and obtain the token and then use that Token and use it in a GET method to access some data.
As you will see in the code, I currently have the logic of the POST apart and the GET apart, but my intention is to be able to have an endpoint that uses both methods.
The idea would be that after the POST method returns the token to me, I can use it later in the GET method.
I will appreciate your help and your prompt response!
code
app.post('/api/datas/login', async(req, res) =>{
const url = '...';
const options = {
email: process.env.EMAIL,
password: process.env.PASSWORD
}
const call = await axios.post(url, options)
const token = call.status === 200 ? call.data.token : null;
res.send({
status: call.status,
message: 'Logged In'
})
});
app.get('/api/datas/alldata', async(req, res) =>{
try {
const url = '...'
const call = await axios.get(url,{
headers: {
"Authorization" : `Bearer ${token}` //I need to use the token value from the POST method here!
}
});
const data = call.status === 200 ? call.data : null;
console.log(data);
res.status(200).json(data);
} catch (error) {
res.status(500).send({ message: error });
}
})
Yes, it should be possible (though not recommended) if you use app.all() instead of post() or get().
You can get the method of the request and act accordingly by looking at req.method.
For more info: https://expressjs.com/en/guide/routing.html

Expressjs router with Firestore resolves before data is retrieved

EDIT: I found out that "async" could be added to the function signature, and while the output does go in the proper order, I still get an error that I can't set headers after they are sent, even though I am not setting them anywhere else. I've modified the code to reflect this.
I'm having an issue with my Google Firestore api using ExpressJS. It seems that the result is sent before the Firestore query completes and I'm not sure why, as I'm not doing anything with res otherwise. It seems that Firestore queries are async but I don't know how to have my endpoint wait for the Firestore data before sending results. Here is my router code:
router.post('/some_endpoint/get_something', async function (req, res) {
console.log("Getting firestore data...")
let db_data = null;
let some_val = req.body.some_val;
let colRef = db.collection("some_collection");
await colRef.where("some_field", "==", some_val)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log("Still processing...")
db_data = doc.data()
})
res.json({ <---- This is where it breaks
status: 200,
data: db_data
})
})
.catch(function(error) {
console.log("Error getting doc: ", error);
})
console.log("We're done!")
});
This is the output order (EDIT with new output order):
Getting firestore data...
Still processing...
Error getting doc: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client...
We're done!
The error message is telling you that you're trying to send multiple responses, which is not valid. Here, your code is calling res.json() many times, once for each document in the query results:
querySnapshot.forEach(function(doc) {
console.log("Still processing...")
res.json({
status: 200,
data: doc.data()
})
})
You should only call res.json() once with the final result to send to the client, after you're done iterating the results.

Get body of GET request (NodeJS + axios)

Here's my request:
axios.get(BASE_URI + '/birds/random', {Stuff: "STUFF"})
.then(randBird=>{
const birdData = randBird.data
const bird = {
age: birdData.age,
bio: birdData.profile.bio,
displayname: birdData.profile.displayname,
species: birdData.profile.species,
_id: birdData._id
}
this.setState({currentBird:bird})
})
Here's what happens on my router (on '/birds'):
birdRouter.route('/random').get((req, res)=>{
console.log('req.body = ', req.body)
User.count().exec((err, num)=>{
if(err){
console.log(err)
return res.send({error: err})
}
const random = Math.floor(Math.random() * num)
User.findOne().skip(random).exec((err, bird)=>{
if(err){
console.log(err)
return res.send({error: err})
}
console.log(bird)
res.send(bird)
})
})
Really, the only lines that are worth paying attention to in both snippets are the first and first two (for the first and second snippet, respectively).
The request goes through, but my console.log shows this:
req.body = {}
What did I do wrong here?
Some browsers and libraries don't support HTTP get method with a body. You can switch to POST/PUT and see if it works as expected.
Usually in GET method we are not passing body data. instead of body data you can pass in query string. and also if you are using express server than you need to install a package body-parser to get data in body. please take a reference of issue posted in axios

Append a query param to a GET request?

I'm trying to make a simple API that calls another API that will return some information. The thing is, in order to connect to the second API, I need to attach query parameters to it.
So what I've tried to do so far is to use an axios.get in order to fetch the API. If I didn't need to add queries on top of that, then this would be really simple but I'm having a really hard time trying to figure out how to attach queries on top of my request.
I've created an object that pulled the original query from my end and then I used JSON.stringify in order to turn the object I made into a JSON. Then, from my understanding of Axios, you can attach params my separating the URL with a comma.
On line 6, I wasn't sure if variables would carry over but I definitely can't have the tag var turned into the string "tag", so that's why I left it with the curly brackets and the back ticks. If that's wrong, then please correct me as to how to do it properly.
the var tag is the name of the query that I extracted from my end. That tag is what needs to be transferred over to the Axios GET request.
app.get('/api/posts', async (req, res) => {
try {
const url = 'https://myurl.com/blah/blah';
let tag = req.query.tag;
objParam = {
tag: `${tag}`
};
jsonParam = JSON.stringify(objParam);
let response = await axios.get(url, jsonParam);
res.json(response);
} catch (err) {
res.send(err);
}
});
response is SUPPOSED to equal a JSON file that I'm making the request to.
What I'm actually getting is a Error 400, which makes me think that somehow, the URL that Axios is getting along with the params aren't lining up. (Is there a way to check where the Axios request is going to? If I could see what the actual url that axios is firing off too, then it could help me fix my problem)
Ideally, this is the flow that I want to achieve. Something is wrong with it but I'm not quite sure where the error is.
-> I make a request to MY api, using the query "science" for example
-> Through my API, Axios makes a GET request to:
https://myurl.com/blah/blah?tag=science
-> I get a response with the JSON from the GET request
-> my API displays the JSON file
After looking at Axios' README, it looks like the second argument needs the key params. You can try:
app.get('/api/posts', async (req, res, next) => {
try {
const url = 'https://myurl.com/blah/blah';
const options = {
params: { tag: req.query.tag }
};
const response = await axios.get(url, options);
res.json(response.data);
} catch (err) {
// Be sure to call next() if you aren't handling the error.
next(err);
}
});
If the above method does not work, you can look into query-string.
const querystring = require('query-string');
app.get('/api/posts', async (req, res, next) => {
try {
const url = 'https://myurl.com/blah/blah?' +
querystring.stringify({ tag: req.params.tag });
const response = await axios.get(url);
res.json(response.data);
} catch (err) {
next(err);
}
});
Responding to your comment, yes, you can combine multiple Axios responses. For example, if I am expecting an object literal to be my response.data, I can do:
const response1 = await axios.get(url1)
const response2 = await axios.get(url2)
const response3 = await axios.get(url3)
const combined = [
{ ...response1.data },
{ ...response2.data },
{ ...response3.data }
]

Categories

Resources