Express JS - Including the optional parameter not working - javascript

I have a problem with doing Pagination. when including multiple & parameters. simply say, it doesn't work.
server.get("/search", async(req, res) => {
try {
const key = req.query.key;
const value = req.query.value;
const text = req.query.text;
let result = await collection.aggregate([
{
'$search': {
'text': {
'query': `${text}`,
'path': 'title'
}
}
},
//match key here...
]).toArray();
res.send(result)
} catch (error) {
console.error(error)
}
})

The problem you have there is how you structured your endpoint url.
app.get("/search/:text/:key?&:value?&.....", (req,res)) => {....}
If you want to get the values you send via query string, you don't have to add the query params to the endpoint's url, you can simply have it like so:
app.get("/search", (req,res)) => {....}
And then build the request to the API like this:
http://localhost:4000/search?text=mango&brand=rasna
Like this you can access the properties of the request in the route's controller:
app.get("/search", (req,res)) => {
const { text, brand } = req.query;
}
Optional values are fine, if you don't send them they will be undefined when you try to access their values in the controller so you can just check for them with conditionals.
app.get("/search", (req, res)) => {
const { text, brand } = req.query;
if(text) { ... }
if(brand) { ... }
}
Obviously this is a very simple implementation just to explain the problem.

Related

I want to know how to got COUNT from SQL in reactjs

my request is good but i want to know how can i use my response in React.
SQL request :
```
exports.countAllComments = async (req, res) => {
const pId = req.params.id;
db.query(
"SELECT COUNT(*) FROM comments WHERE post_id = ?",
[pId],
(err, count) => {
if (err) {
res.status(500).json({ err });
console.log(err);
} else {
console.log(count)
res.status(200).json(count);
}
}
);
};
```
Front for fetch count:
```
const [countData, setCountData] = useState(0);
useEffect(() => {
const fetchCount = async () => {
try {
const fetchData = await Axios.get(
`http://localhost:3001/api/post/comment-count/${post.id}`,
{
headers: { Authorization: `Bearer ${test1.token}` },
}
);
setCountData(fetchData.data[0]);
} catch (err) {}
};
fetchCount();
}, [post.id, test1.token]);
console.log(countData);
```
console log return : "{COUNT(*): 4}" how can i get (4)
given your trivial example, the trivial solution would be something like -
fetchData.data[0]['COUNT(*)']
however, you should really have a think about the contract on the API, and enforce a certain return type from your API, and not just simply return the response from the SQL query. i.e. your API could possibly return an object like -
{ count: x }
where its up to your API to transform the result from the SQL query in a way that satisfies the contract, that way your React client is disconnected from your database layer and only cares about your API contract.
That way your client side becomes something like -
fetchData.data.count
which wouldn't break if the query where to be updated in some way etc.

Axios response data is not saved with useState

While trying to fetch data from my express backend and MySQL database, with my react frontend using axios, it fails to set the fetched data using useState
my frontend function looks like this
const searchUser = () => {
Axios.post("http://localhost:3001/searchUser", {
username: username,
}).then((response) => {
if (response.data) {
setResult(response.data);
}
});
};
and my backend function looks like this
const searchUser = (req, res) => {
const keyword = req.body.username;
db.query(
"SELECT id,username FROM users WHERE username like ?",
"%" + keyword + "%",
(err, result) => {
if (err) {
res.json({ message: err });
console.log(err);
} else {
console.log(result);
res.json({ result });
}
}
);
};
I tried many methods while saving the data with the useState hook, I appreciate any help
While using Promises and then instead of async / await make sure to catch the errors if your fetch fails.
Unless you share with us the whole component that contains the searchUser function and how you defined the state i cannot pin point you on the error.
What i suggest you to do is adding a catch to your fetch by doing the following:
const searchUser = () => {
Axios.post("http://localhost:3001/searchUser", {
username: username,
}).then((response) => {
if (response.data) {
setResult(response.data);
}
}).catch((error) => {
console.error(error);
});
};
If any abnormalities has happened in your request the catch will tell you! Don't underestimate it's power.
Another path you can look into is console logging your output in front end searchUser function just before setting it in the state.
I did solve the problem, just by replacing res.json({ result }); to res.json(result); in the last line in my backend function

Can not do get request method because data says [object object]

I'm trying to do a get request method in Vue and Express to get data based on my v-model.
Below is my code that tries to send data to express.
getResult() {
axios
.get(
`${process.env.VUE_APP_API}/hospita/result/` +
{
hosp_name: "SAMPLE"
}
)
.then(res => console.log(res.data))
.catch(err => console.log(err));
}
and here is my get request method that receives the data coming from vuejs
router.get('/result/', (req, res) => {
const sql = "SELECT * FROM \
ND_HOSP WHERE hosp_ptype = 'h' AND hosp_name LIKE ?";
console.log(req.body)
myDB.query(sql, ['%' + req.body.hosp_name + '%'], (err, result) => {
if (err) {
console.log(err)
} else {
try {
res.send(result);
/* console.log(result) */
} catch (err) {
res.send(err)
}
}
})
})
but it gives me error and says
http://localhost:9002/hospita/result/[object%20Object]
In your getResult() let's to change method to post and + to , for passing your data in body. You can look at this code below:
getResult() {
axios
.post( // <= change method to post
`${process.env.VUE_APP_API}/hospita/result/`, // change `+` with `,`
{
hosp_name: "SAMPLE"
}
)
.then(res => console.log(res.data))
.catch(err => console.log(err));
}
After that, don't forget to change your router method from get to post. You can look at this code below:
// change method `get` to `post`
router.post('/result/', (req, res) => {
const sql = "SELECT * FROM \
ND_HOSP WHERE hosp_ptype = 'h' AND hosp_name LIKE ?";
console.log(req.body)
myDB.query(sql, ['%' + req.body.hosp_name + '%'], (err, result) => {
if (err) {
res.send(err)
} else {
res.send(result);
}
})
})
Make sure, because we're use the req.body, so, don't forget to add body parser in your server.js or app.js. It's will looks like this code below:
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
I hope it can help you.
problem is here: res.send(result);
result is not containing json data, it is containing any other object or blank object like {}.
so first of all try to see what is inside the result using console.log().
most of the time for the such cases two functions are very useful.
JSON.stringify(object);
JSON.parse(strobj);

What is the best way to do nested API calls with oauth in node.js?

I am writing an API that fetches data from twitter using the oauth v1 API and serves it for my webapp.
I have one api endpoint that fetches from Twitter an array of objects representing each of the lists a user has created.
I have another api endpoint that, given a list ID, fetched an array of all the members of that list.
I want to combine these two endpoints into one, so my webapp can request '/api/getAllLists' and it will receive an array of list objects (API 1), with one of the properties of the object being a full list of members (API 2).
I have got myself tangled up trying to work out how to do this - I have used promises and async functions before but I don't know the best way to accomplish this.
router.get('/getAllLists', isLoggedIn, (req, res) => {
//oauth access credentials
let {oauthAccessToken, oauthAccessTokenSecret, username, user_id} = req.cookies.twitter || '';
//first api call to get array of list objects
consumer.get("https://api.twitter.com/1.1/lists/list.json?user_id="+user_id, oauthAccessToken, oauthAccessTokenSecret, (error, data, response) => {
if (error) {
console.log(error)
} else {
data = JSON.parse(data).map((list) => {
let newList = list;
//second API call, using list.id_str fromt he first call
consumer.get("https://api.twitter.com/1.1/lists/members.json?list_id="+list.id_str, oauthAccessToken, oauthAccessTokenSecret, (error, data, response) => {
if (error) {
console.log(error);
} else {
newList.contents = data;
return newList;
}
});
return newList;
})
res.send(data);
}
});
});
I have accomplished what I was aiming for like this:
//oauth access credentials
let { oauthAccessToken, oauthAccessTokenSecret, username, user_id } = req.cookies.twitter || '';
consumer.get("https://api.twitter.com/1.1/lists/list.json?user_id=" + user_id, oauthAccessToken, oauthAccessTokenSecret, (error, data, response) => {
if (error) {
console.log(error)
} else {
let allLists = [];
let allListLength = JSON.parse(data).length;
let listCounter = 0;
const addToAllLists = (list) => {
allLists.push(list)
listCounter ++;
if(listCounter === allListLength) {
res.send(allLists)
}
}
JSON.parse(data).map((list,i) => {
let newList = list;
consumer.get("https://api.twitter.com/1.1/lists/members.json?count=4999&list_id=" + list.id_str, oauthAccessToken, oauthAccessTokenSecret, (error, data2, response) => {
if (error) {
console.log(error);
} else {
newList.users = JSON.parse(data2).users;
addToAllLists(newList)
return newList;
}
})
})
}
});
I definitely don't think theis is the best practice method though, and I'd still love to see anyone else's suggestions or corrections, thanks.

express.js - how to intercept response.send() / response.json()

Lets say I have multiple places where I call response.send(someData). Now I want to create a single global interceptor where I catch all .send methods and make some changes to someData. Is there any way in express.js? (hooks, listeners, interceptors, ...)?
You can define a middleware as below (taken and modified from this answer)
function modifyResponseBody(req, res, next) {
var oldSend = res.send;
res.send = function(data){
// arguments[0] (or `data`) contains the response body
arguments[0] = "modified : " + arguments[0];
oldSend.apply(res, arguments);
}
next();
}
app.use(modifyResponseBody);
for those finding on google, based off the top answer:
app.use((req, res, next) => {
const oldSend = res.send
res.send = function(data) {
console.log(data) // do something with the data
res.send = oldSend // set function back to avoid the 'double-send'
return res.send(data) // just call as normal with data
}
next()
})
Yes this is possible. There are two ways to do this, one is to use a library that provides the interception, with the ability to run it based on a specific condition:
https://www.npmjs.com/package/express-interceptor
The other option is to just create your own middleware (for express) as follows:
function modify(req, res, next){
res.body = "this is the modified/new response";
next();
}
express.use(modify);
Just want to provide a practical usage example with intercepting res.json.
When we're writing express server, we might send the status and message in every response according to the situation like below.
app.post('/test', (req, res) => {
res.json({status: 1, message: "some_error", otherData: "nothing"})
})
But, what if I don't want to write the status and message in every time? I could add new function to build a template response body to send the data when using res.json.
const messageMap = {
0: "success",
1: "some_error"
}
app.use((req, res, next) => {
const originJson = res.json
res.json = (status, jsonData) => {
const fixedResponse = {
status,
message: messageMap[status]
}
originJson.call(res, {...jsonData, ...fixedResponse})
}
next()
})
Then I just need to use below function.
app.get("/test", (req, res) => {
res.json(1, {otherData: 1})
})
You can even use builder pattern to do this.
app.use((req, res) => {
res.buildFixedResponse = function (status) {
const fixedResponse = {
status,
message: messageMap[status]
}
res.json = function (jsonData) {
originJson.call(this, {...jsonData, ...fixedResponse})
}
return this
}
})
Then trigger function like below.
app.get("/test", (req, res) => {
res.buildFixedResponse(1).json({otherData: 1})
})
For my case, I had to use a middleware with typicode/json-server and be able to get a different response object than just a blunt javascript array.
While the typicode/json-server response was something like:
[
{
...
}
]
After applying the middleware:
module.exports = (req, res, next) => {
const oldSend = res.send;
res.send = (data) => {
const oldData = JSON.parse(data);
// we want to change the response only if a blunt array is sent
// also, we do this for the old sake of not sending json arrays
if(Object.prototype.toString.call(oldData) === '[object Array]') {
data = {
data: oldData
};
}
res.send = oldSend;
return res.send(data);
};
next();
}
The response looks as follows:
{
data: [
{
...
}
]
}
You can simply do it using NODEJS and Express, say you are calling an API and want to send modify the data before sending response back.
router.get('/id', (req,res) => {
... //your code here filling DATA
let testData = {
"C1": "Data1",
"C2": "Data2",
"yourdata": DATA
};
res.send(testData);
});

Categories

Resources