I was trying to use qs as recommended by hapi's documentation (see https://hapi.dev/tutorials/routing/?lang=en_US#query) however unsurprisingly, it did not work.
The documentation recommends something like this:
const Hapi = require('@hapi/hapi');
const Qs = require('qs');
const server = Hapi.server({
port: 3000,
host: 'localhost',
query: {
parser: (query) => Qs.parse(query)
}
});
...
The problem is that the query parameter in server.options.query.parser is an object not a string (See). For that reason, Qs.parse(query) is wrong since Qs.parse expects a string.
To get things working, I am manually building a query string; something like:
const query = [];
for (const key in request.query) {
query.push(`${key}=${request.query[key]}`);
}
const opts = parse(query.join('&'));
Is there an undocumented way to receive the raw query string or to convert request.query to a string?
I already opened an issue in the hapi.dev repo (https://github.com/hapijs/hapi.dev/issues/297) but I was directed to report here.
I'm having the exact same issue, after update @hapi/hapi to v19.0.1 I can't access any of my GET routes because Joi will fail when expecting an array but since all values were converted to string I now receive literally a string with a square bracket inside "[]" (or any value that was passed in the request)
I've created a gist here to easily recreate the problem, when reaching http://localhost:3333/test?status=a,b
Without any validator, request.query is partially parsed. Which seems to be the normal behavior as explained here in the documentation but later it say to use server.options.query.parser with qs. However as @tundebabzy said, qs.parse expect a string, not an object but the argument passed to the parser function is cleary an object (see)
The problem seems to happen somewhere here:
https://github.com/hapijs/hapi/blob/5796cd9fc1a1053917544046f317eb0370bab01e/lib/request.js#L169-L171
as url.searchParams is then passed to this._parseQuery here
https://github.com/hapijs/hapi/blob/5796cd9fc1a1053917544046f317eb0370bab01e/lib/request.js#L147
Hope this help.
Having the same issue. According to https://github.com/ljharb/qs/issues/357 the qs confirms to support only strings for parsing parameters.
Maybe there could be an extra string parameter to parse function in addition to an object?
For example, changing the _setUrl function
https://github.com/hapijs/hapi/blob/d064f9c935627f26494345903671379302b0d198/lib/request.js#L144-L149
like this
this._parseQuery(url.searchParams, url.search);
And add then add search parameter to the caller here
https://github.com/hapijs/hapi/blob/d064f9c935627f26494345903671379302b0d198/lib/request.js#L236
note: qs.parse does in fact support an object parameter (although the docs only talk about a string, since that's the primary use case) but it assumes that in the object form, all the values have been parsed already (meaning, if you use the "comma" option, the object's values need to already have been split into arrays)
const Hapi = require('@hapi/hapi');
const Qs = require('qs');
const server = Hapi.server({
port: 3000,
host: 'localhost',
query: {
parser: (query) => Qs.parse(query)
}
});
server.route({ path: '/', method: 'GET', handler: (request) => request.query });
server.start();
and...
$ curl http://localhost:3000/?s=4
> {"s":"4"}
$ curl http://localhost:3000/?s[a]=4
> {"s":{"a":"4"}}
I don't see a problem.
I believe the issue is if you parse with the “comma” array format enabled, fwiw.
Yes, it doesn't work for parsing arrays, even with
Qs.parse(query, {comma: true})
http://localhost:3000/?s=1,2,3,4,5
Thanks @ljharb.
I consider this a qs/usage issue. hapi is not going to implement custom logic. If qs does not want to properly support its own API where you can pass either a string or an object with each key=value pair literals, then someone has to write a wrapper that implements the comma stuff...
Most helpful comment
I'm having the exact same issue, after update
@hapi/hapitov19.0.1I can't access any of myGETroutes because Joi will fail when expecting an array but since all values were converted to string I now receive literally a string with a square bracket inside"[]"(or any value that was passed in the request)I've created a gist here to easily recreate the problem, when reaching http://localhost:3333/test?status=a,b
Without any validator,
request.queryis partially parsed. Which seems to be the normal behavior as explained here in the documentation but later it say to useserver.options.query.parserwithqs. However as @tundebabzy said,qs.parseexpect a string, not anobjectbut the argument passed to the parser function is cleary an object (see)The problem seems to happen somewhere here:
https://github.com/hapijs/hapi/blob/5796cd9fc1a1053917544046f317eb0370bab01e/lib/request.js#L169-L171
as
url.searchParamsis then passed tothis._parseQueryherehttps://github.com/hapijs/hapi/blob/5796cd9fc1a1053917544046f317eb0370bab01e/lib/request.js#L147
Hope this help.