gcanti / fp-ts-routing

A type-safe bidirectional routing library for TypeScript

Home Page:https://gcanti.github.io/fp-ts-routing/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Null / Undefined parameters are not removed from URI

Eldow opened this issue · comments

I faced an issue while sending null values as query parameters, they were converted to empty strings by node's querystring module. Removing them before stringifying the query fixed that.

  toString(encode = true) {
    const nonNullQuery = filterMap(this.query, fromNullable) // <-- removing null or undef params
    const qs = querystring.stringify(nonNullQuery)
    const parts = encode ? this.parts.map(encodeURIComponent) : this.parts
    return `/${parts.join('/') + (qs ? `?${qs}` : '')}`
  }

@gcanti What do you think about it ?

@Eldow may you provide a PR?

I'm not sure we should modify how querystring.stringify works.

query accepts t.Type<A, Query> so you can pick a suitable decoder/encoder

Example

import { fromNullable } from 'fp-ts/lib/Option'
import { filterMap } from 'fp-ts/lib/Record'
import * as t from 'io-ts'
import { mapOutput } from 'io-ts-types'
import { query, Route } from '../src'

const T = mapOutput(t.type({ a: t.union([t.string, t.undefined, t.null]) }), o => filterMap(o, fromNullable))

const match = query(T)

const route = new Route([], {})

console.log(match.formatter.run(route, { a: undefined }).toString())
// => '/'
console.log(match.formatter.run(route, { a: null }).toString())
// => '/'

Actually querystring.stringify does not handle nulls; it silently converts to empty string; which is wrong if your type is number | null.

The problem is not querystring.stringify but the values we send it in the object.

That's inconsistent.

Due to that problem; this is not working

  it('should be reentrant', () => {
    const dummy = lit('x').then(
      query(t.interface({ a: t.union([t.undefined, t.string]) }))
    );
    assert.deepEqual(
      dummy.parser.run(Route.parse(format(dummy.formatter, { a: undefined }))),
      some([{ a: undefined }, Route.empty])
    ); // errors as parsed as: { a: '' }
  });

@sledorze Good point, I agree

so, is the fix proposed by @Eldow acceptable or are you thinking about something else?

Yes it is, @Eldow would you like to send a PR?

On my way !