feathers icon indicating copy to clipboard operation
feathers copied to clipboard

Wanted to have a request with query like {$in: [.....]}, but koa-qs has array limit already inside the feathers koa.

Open arcanys-ivan opened this issue 1 year ago • 2 comments

Wanted to have a request with query like {$in: [.....]}, but koa-qs has array limit already inside the feathers koa.

Is there any way to update the limit or remove it after all? Or this feature will be added soon? or not?

Thanks

Originally posted by @arcanys-ivan in https://github.com/feathersjs/feathers/discussions/3312

arcanys-ivan avatar Jan 24 '24 08:01 arcanys-ivan

I just ran into this limitation as well. qs by default will not parse an array with more than 20 items, it will convert it to an object with numbered indices as keys instead. The query validator rejects this construction and we get a 400 Bad Request with data along these lines:

{
           "instancePath": "/id/$in",
           "schemaPath": "#/properties/id/anyOf/1/properties/%24in/type",
           "keyword": "type",
           "params": {
             "type": "array"
           },
           "message": "must be array"
}

koa-qs supports passing options to qs.parse() since 3.0.0. It would be helpful if @feathersjs/koa either passed { arrayLimit: 0 } into koa-qs or allowed the user to pass in an options object.

Maybe there's another possibility where a koa app that's already had koa-qs applied to it can be passed as the second arg to the koa() fn from @feathersjs/koa?

lvivier avatar Jan 24 '24 21:01 lvivier

fwiw we are working around this with a global hook along these lines:

import { traverse } from 'feathers-hooks-common'
import { isObject } from 'lodash'

const METHODS = ['$in', '$nin', '$ne', '$or', '$and']

export default function queryArrays () {
  return traverse(function (node) {
    if (METHODS.includes(this.key) && isObject(node) && isArrayable(node)) {
      this.update(Object.values(node))
    }
  },
  ctx => ctx.params.query)
}

function isArrayable (obj) {
  return Object.entries(obj).every(([key, value]) => !isNaN(+key) && typeof value === 'string')
}

lvivier avatar Feb 07 '24 23:02 lvivier