Hi,
I am having an issue with the query parameter values being duplicated when building a liberator resource using with-json-mixin. I'm not entirely sure if that's a bug or not, but hopefully we can get more details on this.
What happens is that when a get request is being made with a multi-value query string ie https://some.url?thing=1&thing=2 I would have expected the parsed params to be something like [1 2] but what I see instead is [1 2 1 2 1 2]. As you would expect, if there are any specs configured the request would not be valid.
To have a better understanding on what is happening I have the following tests:
(deftest with-params-parsed-as-json
(testing "using with-json-mixing"
(let [resource
(->
(l/build-resource
(json/with-json-mixin)
{:allowed-methods
[:get]
:handle-ok
(fn [{:keys [request]}]
(let [params (:params request)]
{:correct-params
(and
(= (:thing1 params) [1 2 3])
(= (:thing2 params)
{:key-1 "value"})
(= (:thing3 params) [1 2 1 2 1 2]))}))})
(keyword-params/wrap-keyword-params)
(params/wrap-params))
request (->
(ring/request :get "/")
(ring/header "Content-Type" json/json-media-type)
(ring/query-string
"thing1=[1,2,3]&thing2={\"key1\":\"value\"}&thing3=1&thing3=2"))
response (call-resource resource request)]
(is (= 200 (:status response)))
(is (= {:correct-params true}
(:body response)))))
(testing "without json encoder/decoder"
(let [resource
(->
(l/build-resource
(json/with-json-media-type)
(json/with-body-parsed-as-json)
(json/with-params-parsed-as-json)
{:allowed-methods
[:get]
:handle-ok
(fn [{:keys [request]}]
(let [params (:params request)]
{:correct-params
(and
(= (:thing1 params) [1 2 3])
(= (:thing2 params)
{:key-1 "value"})
(= (:thing3 params) [1 2]))}))})
(keyword-params/wrap-keyword-params)
(params/wrap-params))
request (->
(ring/request :get "/")
(ring/header "Content-Type" json/json-media-type)
(ring/query-string
"thing1=[1,2,3]&thing2={\"key1\":\"value\"}&thing3=1&thing3=2"))
response (call-resource resource request)]
(is (= 200 (:status response)))
(is (= {:correct-params true}
(:body response))))))
As you can see from above the issue occurs when using with-json-mixin, but when leaving out with-json-encoder and with-json-decoder everything seems to be working as expected. It may seem as the issue is somehow related to those 2 mixings even though they're not doing a lot apart from adding a map to the context. Something strange seems to happen within the merge-actions function as this is the point where those params values are being duplicated
(defn merge-actions
[left right]
(fn [context]
(letfn [(execute-and-update [context f]
(liberator/update-context context (f context)))]
(let [left-result (execute-and-update context
(liberator-util/make-function left))
right-result (execute-and-update left-result
(liberator-util/make-function right))]
right-result))))
and more specifically within the liberator update-context which seems to concatenate the vectors within the params unless it's explicitly decorated with the replace metadata as mentioned here. The params are decorated with the replace metadata, but within with-params-parsed-as-json that's the last mixin to be added as part of with-json-mixin and by then the params values have already been duplicated.
As a workaround I've created an internal mixin that takes care of decorating the params with the replace metadata and placed it before with-json-mixin:
(defn- with-replaceable-params []
{:initialize-context
(fn [{:keys [request]}]
{:request {:params (with-meta (:params request) {:replace true})}})})
(defn resource-handler
[dependencies & {:as overrides}]
(build-resource
(with-replaceable-params)
(with-json-mixin dependencies)
overrides))
It would be great to see your thoughts on this, and if you need more details please let me know.
Thanks,
Cris
Hi,
I am having an issue with the query parameter values being duplicated when building a liberator resource using
with-json-mixin. I'm not entirely sure if that's a bug or not, but hopefully we can get more details on this.What happens is that when a get request is being made with a multi-value query string ie
https://some.url?thing=1&thing=2I would have expected the parsed params to be something like[1 2]but what I see instead is[1 2 1 2 1 2]. As you would expect, if there are any specs configured the request would not be valid.To have a better understanding on what is happening I have the following tests:
As you can see from above the issue occurs when using
with-json-mixin, but when leaving outwith-json-encoderandwith-json-decodereverything seems to be working as expected. It may seem as the issue is somehow related to those 2 mixings even though they're not doing a lot apart from adding a map to the context. Something strange seems to happen within the merge-actions function as this is the point where those params values are being duplicatedand more specifically within the liberator
update-contextwhich seems to concatenate the vectors within the params unless it's explicitly decorated with thereplacemetadata as mentioned here. The params are decorated with thereplacemetadata, but withinwith-params-parsed-as-jsonthat's the last mixin to be added as part ofwith-json-mixinand by then the params values have already been duplicated.As a workaround I've created an internal mixin that takes care of decorating the params with the
replacemetadata and placed it beforewith-json-mixin:It would be great to see your thoughts on this, and if you need more details please let me know.
Thanks,
Cris