How to pass an object to a GET request? - node.js

Hi I'm currently trying to pass an object to a GET request for search filter in nodejs using express but I get a return of 404 GET /route1/search/[object%20Object] 404 1.148 ms - 38
I already try to log the result in the terminal using console.log(req.params.dataObject); or console.log(req.params.dataObject.option); but get the result of [Object, Object] or Undefined
router.get('/search/:dataObject',
async function (req, res) {
try {
console.log(req.params.dataObject);
res.status(200).json(searchPhone);
} catch (err) {
return res.status(404).json({
error: err.message
});
}
});
I expect the result to be {option: 'some data', keyword: 'some data'}

You can't shove an object into a URL without encoding it somehow. Whatever code is calling your server is attempting to do that, and JavaScript is converting the object to a string, which is where the [object Object] comes from. This happens before your server ever gets to it.
What you should probably be doing instead is using the querystring. This is a standard way for you pass in key/value parameters. For example, your client would call:
GET /search?option=some%20data&keyword=some%20data
Then in your server, you could use:
req.query.option
req.query.keyword

Related

Why is node.js fetch giving a 'Bad Request' error?

I am getting a 400 error (bad request) from this POST:
siteData.myPost = async function (url, data) {
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(data)
}
try {
const response = await fetch(quilkinUrlBase() + url,options);
return response.json();
}
catch (error) {
qPopup.Alert("Error with web request: " + error);
}
};
(the fetch address computes to "http://localhost:1337/UpdateSiteVisits").
This can't, of course, convert 'response' to json because the response is a DOC containing the 400 error message.
in server.js I have the following callback definition for the URL specified in the fetch:
app.post("/UpdateSiteVisits", sites.updateVisits);
in the debugger, the code never reaches updateVisits().
I have a very similar construct with a GET:
app.get("/GetSitesForType/:type", sites.findByType);
which works fine, so I assume the problem is with the 'options' object (which the GET doesn't use). In the POST case the data is just an integer ID, and if I change the data format to plain text (instead of json), the post works fine.
If leave the format as json, and send an object, rather than a simple integer, the post also works fine. So it looks like the system just doesn't like converting a single integer to json.
I needed to send the integer as json, so instead of using the method like this:
siteData.myPost("UpdateSiteVisits", siteID)
I needed to use
siteData.myPost("UpdateSiteVisits", { siteId: siteID })
[ later ]
Please ignore my question and answer, I was just getting mixed up with types. Such is the result from me converting from strongly-typed C# to untyped javascript!

NodeJs : How to send an object of multiple values with delete request from Angular to Nodejs backend

Explanation of my question:
From my Angular2+ app I am calling a delete request to node js backend. in this delete request, I want to send an object having two values. I am doing it by two Methods here are the snippets. But Both Methods either give me empty Object {} or undefined values. Please Guide me How can I solve this problem.
Method 1: Sending the Object as a payload with delete Request
DeletSingleImageFromRecentWorkGalleryUrl ="http://localhost:7000/work/deleteRecentWorkSingleImage";
Api Request From Angular:
DeleteSingleImageFromRecentWorkGallery(Data) {
let _RequestedObject = {
ImageCategory: Data.ImageCategory,
ImageUrl: Data.ImageUrl
}
return this.http.delete(`${this.DeletSingleImageFromRecentWorkGalleryUrl}`,_RequestedObject);
}
In Response from Nodejs Backend I get Empty Object. Here is the snippet of backend
Api Route
Router.delete('/deleteRecentWorkSingleImage',workController.DeleteSingleImageFromRecentWork);
Api Controller
DeleteSingleImageFromRecentWork : async(req,res)=>{
console.log(req.body);
res.json({
Message:'You have Reached The Delete End Point',
Data:req.body
})
}
Output: Empty Object {}
Method 2: Sending the Object with URL with delete Request
DeletSingleImageFromRecentWorkGalleryUrl ="http://localhost:7000/work/deleteRecentWorkSingleImage/";
Api Request From Angular:
DeleteSingleImageFromRecentWorkGallery(Data) {
let _RequestedObject = {
ImageCategory: Data.ImageCategory,
ImageUrl: Data.ImageUrl
}
return this.http.delete(`${this.DeletSingleImageFromRecentWorkGalleryUrl}${_RequestedObject}`);
}
In Response from Nodejs Backend I get [object object]
but i cannot access the values as it gives me undefined. Here is the snippet of backend
Api Route
Router.delete('/deleteRecentWorkSingleImage/:Data',workController.DeleteSingleImageFromRecentWork);
Api Controller
DeleteSingleImageFromRecentWork : async(req,res)=>{
console.log(req.params.Data);
res.json({
Message:'You have Reached The Delete End Point',
Data:req.params.Data
})
}
Output : [object Object] and when accessing the key pair value it says undefined

axios.post() error about circular structure

Please guide me in case I'm not in proper use of axios. This simple piece of code can directly run:
const axios = require('axios')
axios.post('https://exp.host/--/api/v2/push/send', {"to":["ExponentPushToken[xxxxxxx]"],"title":"test title","body":"test body."})
.then(responseExpo => {
console.log("expo replied normally: " + JSON.stringify(responseExpo));
})
.catch(error => {
console.log("expo replied with error: " + JSON.stringify(error,null,4));
});
The result is:
Promise { <pending> }
expo replied with error: {}
"axios": "^0.19.2"
I tried to post with api tools and see a response with normal 200 status code:
{
"data":[
{
"status": "error",
"message": "\"ExponentPushToken[xxxxxxx]\" is not a registered push notification recipient",
"details":{
"error": "DeviceNotRegistered"
}
}
]
}
(you may ignore the "error": "DeviceNotRegistered" inside this json cos it's expected because I have put an invalid xxxxx input value when calling the api. Even putting a valid input value the result is still returning to the catch block with empty error)
I'm expecting it to return to the then block cos the server actually response with 200 with well formatted json result.
Have I done something wrong so that the call returns to the catch block? Cos the error is empty I have no idea what went wrong.
===============================
after jfriend's reminder I changed to directly disply the error.
console.log("expo replied with error: " + error);
it is show like this now:
Promise { <pending> }
expo replied with error: TypeError: Converting circular structure to JSON
--> starting at object with constructor 'ClientRequest'
| property 'socket' -> object with constructor 'TLSSocket'
--- property '_httpMessage' closes the circle
Anyone can let me know what exactly it means and guide me how to correct my usage?
(problem resolved). the response (responseExpo in the question) is neither a plain data JSON nor a plain string. it is an object with (see github.com/axios/axios#response-schema) some attributes. The real response content is inside "response.data". I was wrongly treating the response to be a plain json object or the http response content.
I had a similar problem and as solution, I used HttpService from nestjs which returns Observable<AxiosResponse<T>>. I fixed the problem by piping and plucking the request like this:
http.put<T>(url, data, config).pipe(pluck('data'))
I had a similar problem with HttpService from nestjs which returns Observable<AxiosResponse<any>>. I resolve with:
this.httpService.post(this.legacyAccessTokenEndpoint, form, { headers: form.getHeaders() }).pipe(map(x => x?.data))

Searching one collection multiple times in one call

I have an array with multiple values which need to be used as queries to search a collection. I am not sure of a way of doing this using one route. for example:
router.get('/', ensureAuthenticated, (req, res) => {
let ArrayOfIds = [id1, id2, id3]
Movie.find({user: req.user.id}).then(items => {
//Something along this lines
items.subscriptions.forEach(subscription => {
Movie.find({user: subscription})
//This wont work beacuse of the callback promise
.then(movies => {
items.push(movies)
})
})
res.render('index/home',
{pageName: 'Movies', items: items})
.catch(err => console.log(err));
});
})
I want to search the same collection (Movie) for each id and add it to the items object. Doing it with a for loop seems to create a set header error. Any ideas?
This S/O response should have your answer...
Error: Can't set headers after they are sent to the client
From the response:
The error "Error: Can't set headers after they are sent." means that
you're already in the Body or Finished state, but some function tried
to set a header or statusCode. When you see this error, try to look
for anything that tries to send a header after some of the body has
already been written. For example, look for callbacks that are
accidentally called twice, or any error that happens after the body is
sent.
In your case, you called res.redirect(), which caused the response to
become Finished. Then your code threw an error (res.req is null). and
since the error happened within your actual function(req, res, next)
(not within a callback), Connect was able to catch it and then tried
to send a 500 error page. But since the headers were already sent,
Node.js's setHeader threw the error that you saw.
It's likely that you're calling res.redirect() multiple times if you're implementing a for-loop.
Maybe if I understand correctly, you can query the collection with list of ids in your case ArrayOfIds into in query of mongo.
Check $in query of mongoDB.
FYI: create some index on that field.

Handling request simltaneously in nodejs and passing it's response using only one res.send

I am developing an API which takes input in XML containing IDs for media and gives output in XMLform with details of given IDs. I am facing a problem while sending the response of second simultaneous request; here the second request goes into loop showing "loading" on postman.
What I am doing is calling a function in app.post which parses the media and gives output in the callback and send it using res.send, but it works only for single request.
While doing parallel request to same API either it goes in loop or it gives can't set the headers after they are sent as I am using res.send but res.send is the only way which I can use to send the response (even the next doesn't work).
var getCompositeData = function(req, res, next){
abc.getData(req.body, function(err, xmlOutput){
if(err){
console.log("error");
} else {
xmlData = xmlOutput
return next()
}
}
app.post(apiUrl, [
rawBodyParser({
type: 'application/xml'
}),
app.oauth.authorise()
], getCompositeData, function (req, res) {
res.setHeader('Content-Type', 'application/xml');
res.send(xmlData);
});
There are several issues with your code:
if (err) {
console.log("error");
}
If an error occurs, you still need to make sure a response will be sent back, otherwise the request will stall until a timeout happens. You can pass an error to next, and Express will handle it:
if (err) {
return next(err);
}
Next problem:
xmlData = xmlOutput
xmlData is an undeclared variable, which gets overwritten with each request. If two requests happens at (almost) the same time, it's likely that one client gets back an incorrect response (remember, Node.js runs JS code in a single thread; there is not thread-local storage so xmlData gets shared between all requests).
A good place to "store" this sort of data is in res.locals:
res.locals.xmlData = xmlOutput;
return next();
// and later:
res.send(res.locals.xmlData);

Resources