In the front end, I use jQuery to send a GET request like this:
$.get('/api', {foo:123, bar:'123'), callback);
according to jQuery doc, the 2nd parameter is a plain object that will be converted into query string of the GET request.
In my node express back end, I use body-parser like this:
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/api', (req, res) => {
console.log(req.query) // req.query should be the {foo:123, bar:'123'} I sent
});
However, req.query turns out to become {foo:'123', bar: '123'} where all the numbers were converted to strings. How can I revert to the exact same object I sent from front end?
Thanks!
HTTP understands that everything is a string same goes for query string parameters. In short, it is not possible. Just convert your data to integer using parseInt()
example
app.get('/api', (req, res) => {
console.log(parseInt(req.query.bar)) // req.query should be the {foo:123, bar:'123'} I sent
});
I wrote this snippet which parses the convertible ones:
query = Object.entries(req.query).reduce((acc, [key, value]) => {
acc[key] = isNaN(+value) ? value : +value
return acc
},{})
Related
I have developed an API in express that returns text and images separately in two different calls, but for performance reasons I would like to return the text and image (probably in a blob object) in the same response.
Now I'm doing it with the res.send() and res.sendFile() methods but I haven't been able to read anything in the documentation about how to send both at the same time. How could I do it?
Examples of what I'm doing now:
async getImage(req, res){
//Doing things with req
let mypath = './foo/bar'
let file = new Blob(path.resolve(mypath), {type: 'image/png'});
return res.sendFile(file)
}
async getText(req, res){
// Doing things with req
return res.status(200).send({ message: 'foo' })
}
Hy everyone !
I've stored a simple object in Async Storage in a ReactNative app.
But when I get it back, it isn't correctly parsed : all keys still got the quotes marks (added by JSON.stringify() when storing it) ...
I store data like that:
const storeData = () => {
let myData = {
title: 'Hummus',
price: '6.90',
id: '1'
}
AsyncStorage.setItem('#storage_Key', JSON.stringify(myData));
}
and then access data like that:
const getData= async () => {
const jsonValue = await AsyncStorage.getItem('#storage_Key')
console.log(jsonValue);
return JSON.parse(jsonValue);
}
and my object after parsing looks like that:
{"title":"Hummus","price":"6.90","id":"1"}
Any idea why quotes aren't removed from keys ??
That's because JSON specification says the keys should be string. What you are using is the modern representation of JSON called JSON5 (https://json5.org/). JSON5 is a superset of JSON specification and it does not require keys to be surrounded by quotes in some cases. When you stringify, it returns the result in JSON format.
Both JSON and JSON5 are equally valid in modern browsers. So, you should not be worries about breaking anything programmatically just because they look different.
You can use JSON5 as shown below and it will give you your desired Stringified result.
let myData = {
title: 'Hummus',
price: '6.90',
id: '1'
}
console.log(JSON5.stringify(myData));
console.log(JSON.stringify(myData));
<script src="https://unpkg.com/json5#^2.0.0/dist/index.min.js"></script>
Like this:
// JSON5.stringify
{title:'Hummus',price:'6.90',id:'1'}
// JSON.stringify
{"title":"Hummus","price":"6.90","id":"1"}
I am writing a data fetching service on an Express backend. It needs to fetch data from a graphQL endpoint.
I get the following error. I know it's descriptive of the issue but I don't understand it.
'GraphQL queries must be strings. It looks like you\\'re sending the internal graphql-js representation of a parsed query in your request instead of a request in the GraphQL query language. You can convert an AST to a string using the `print` function
from `graphql`, or use a client like `apollo-client` which converts the internal representation to a string for you.' }
This is the function I am using:
fetchMultipleProducts(first : Number, offset : number){
fetch({
query: gql`
query {
getProduct(query: {}, first : ${first}, offset : ${offset}) {
id
code
}
}
`
})
.then(res => {
Logger.info("Fetched data");
console.log(res);
return res;
})
.catch(err => {
Logger.error("Failed to fetch", err);
});
I am trying to pass in variables into it, I assume that's allowed? And using the Gql tag is standard?
Some help would be appreciated, thanks guys.
I removed the Gql tag and sent a string as instructed in the error message. Apologies for my silliness.
I have the following express routes defined:
// Questions Routes
app.route('/questions')
.get(questions.list)
.post(users.requiresLogin, questions.create);
app.route('/questions/:questionId')
.get(questions.read)
.put(users.requiresLogin, questions.hasAuthorization, questions.update)
.delete(users.requiresLogin, questions.hasAuthorization, questions.delete);
app.route('/questions/list/:page')
.get(questions.questionList);
app.route('/questions/count/')
.get(questions.count);
Along with this callback trigger for the questionId route parameter:
app.param('questionId', questions.questionByID);
The expected behavior was to have /questions/count requests route to the count method in a controller, but it is instead being routed to the questionByID method and I'm seeing this error:
CastError: Cast to ObjectId failed for value "count" at path "_id"
...
at exports.questionByID (/path/controllers/questions.server.controller.js:137:56)
...
I think this appears because mongoose is trying to convert the literal "count" from the route to an ObjectId type, which would make sense if I was using the /questions/:questionId route but it doesn't if I'm using /questions/count to make the request.
These are the two relevant methods in questions.server.controller.js
exports.count = function (req, res) {
console.log('attempting to count these damn questions!');
Question.count({}, function (err, count) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
console.log(count);
res.jsonp(count);
}
});
};
/**
* Question middleware
*/
exports.questionByID = function (req, res, next, id) {
Question.findById(id).populate('user', 'displayName').exec(function (err, question) {
if (err) return next(err);
if (!question) return next(new Error('Failed to load Question ' + id));
req.question = question;
next();
});
};
I've fixed it by setting the route to:
app.route('/questionscount')
.get(questions.count);
But it looks bad and I don't want to do it like that, does anyone know why this is happening?
Thanks in advance.
Since express evaluates the routes in addition order, you should put the more specific routes first. In your example it just evaluates "count" as the questionId parameter because it matches the expression.
If you put the app.route('/questions/count/') route before the
app.route('/questions/:questionId') it should work.
If count and question_id have diffirence you can put Regex to route for distinguish them
I think this might be a basic question, but looking for the best approach.
I'm building an express app that should route to one of four different Mongoose models depending on the route.
Something like this:
app.get('/:trial', function(req, res){
var trial = req.params.trial;
trial.find(function(err, records) {
if (err)
res.send(err);
res.json(records); // returns all trial records in JSON format
});
});
I have 4 mongoose models named: trial1, trial2, trial3, trial4. I would like the trial parameter of the URL to determine which collection gets queried. Obviously the above won't work, but what should I do instead of rewriting the route four times instead?
Thanks in advance!
You can get models by name:
var mongoose = require('mongoose');
app.get('/:trial', function(req, res){
var trial = req.params.trial;
mongoose.Model(trial).find(function(err, records) {
if (err) {
// Return when we end the response here...
return res.send(err);
}
res.json(records); // returns all trial records in JSON format
});
});
Depending on circumstances, I would validate the value of trial first (so requesting /User doesn't dump all users to the client, for instance).