klaemo opened a new issue, #377:
URL: https://github.com/apache/couchdb-nano/issues/377
## Expected Behavior
A query option whose value is `undefined` is left out of the request URL, as
nano 10 did. For example, `db.view('ddoc', 'view', { limit: undefined,
include_docs: true })` should request
`/_design/ddoc/_view/view?include_docs=true`.
## Current Behavior
Since the switch from axios to `fetch` in 11.0.0 (#314), `relax()` builds
the query string with `new URLSearchParams(qs)`. `URLSearchParams` turns
`undefined` into the string `"undefined"`, so the option is sent as
`key=undefined`. For `startkey`/`endkey`/`key`/`keys`/`start_key`/`end_key` the
same thing happens one step earlier: `JSON.stringify(undefined)` returns
`undefined`, which is then serialised the same way.
Requests that fail against CouchDB 3.3.3 with nano 11.0.7 (and current
`main`, 53dea92):
| call | request | CouchDB response |
| --- | --- | --- |
| `db.view('guests', 'by-email', { keys, limit: undefined, include_docs:
true })` | `POST …/_view/by-email?limit=undefined&include_docs=true` | `400
query_parse_error: Invalid value for integer: "undefined"` |
| `db.view(ddoc, view, { start_key: undefined, end_key: undefined, group:
true })` | `GET …?start_key=undefined&end_key=undefined&group=true` | `400
bad_request: invalid UTF-8 JSON` |
| `db.view(ddoc, view, { keys: undefined, reduce: false })` | `GET
…?keys=undefined&reduce=false` (`keys` is falsy, so `view()` doesn't move it to
a POST body) | rejected: `keys=undefined` isn't valid JSON |
nano 10 serialised `params` with the `qs` library (`paramsSerializer`),
which skips `undefined` values, so the same code worked there. Request bodies
aren't affected: `JSON.stringify` already drops `undefined`, so `db.search`,
`db.find` and the `keys`/`queries` POST bodies behave correctly.
## Possible Solution
In `relax()`, after the JSON-encoding loop for the key parameters, delete
any `qs` entry whose value is `undefined`. That covers every API that passes
`qs` through `relax()`, not just views.
I'd leave `null` alone. `startkey: null` is a valid CouchDB key and is
correctly sent as `startkey=null` after JSON encoding. For other parameters
`null` is an explicit value from the caller, and nano 10 didn't drop it either
(`qs` serialised it as `key=`).
I'm happy to send a PR with tests.
## Steps to Reproduce (for bugs)
1. `npm install [email protected]`
2. Run against any CouchDB 3.x database with a design document `ddoc`
containing a map view `view`:
```js
const nano = require('nano')('http://admin:[email protected]:5984')
const db = nano.db.use('mydb')
await db.view('ddoc', 'view', { limit: undefined, include_docs: true })
```
3. The request is `GET
/mydb/_design/ddoc/_view/view?limit=undefined&include_docs=true`. You can see
it in CouchDB's request log or through a proxy. nano's own debug log omits the
query string.
4. CouchDB rejects it with `400 query_parse_error: Invalid value for
integer: "undefined"`.
## Context
We hit this while upgrading an app from nano 10.1.4 to 11.0.7. Passing
optional values straight through, e.g. `{ limit: opts.limit, keys: opts.keys
}`, is a common pattern that worked with nano 10. With nano 11 every caller has
to strip `undefined` values itself. The migration guide doesn't mention this,
and it fails at runtime with 400s rather than at compile time.
## Your Environment
* Version used: nano 11.0.7 (also reproduced on `main` at 53dea92); CouchDB
3.3.3
* Browser Name and version: n/a (Node.js 24.21.0)
* Operating System and version (desktop or mobile): Linux (Ubuntu, kernel
6.8)
* Link to your project: https://github.com/klaemo/guestlist (upgrade PR:
https://github.com/klaemo/guestlist/pull/118)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]