Strange duplication in vector of strings when using the context to store values between handlers

74 views
Skip to first unread message

Erik Bakstad

unread,
Jul 18, 2013, 9:31:00 AM7/18/13
to clojure-...@googlegroups.com
Hi. I noticed something strange when storing data in the context re-using the same key. I lookup a value in :allowed? and store it in the ::instance key of the context. If it's a PUT I assoc the result of the update to ::instance and return it in :handle-ok. For some strange reason, this causes a duplication in the vector :children? 

Here the boild down version of our code:

(defresource put-delete-get [system path id json-body {:keys [find-by-id find-versions
                                                              create update delete-by-id validation-fn
                                                              has-permission] :or {has-permission (constantly true)}}]
  :allowed-methods [:put :delete :get]
  :available-media-types ["application/json"]
  :allowed? (fn [{{method :request-method} :request}]
                  {::instance (find-by-id system id)})
  :exists? ::instance
  :can-put-to-missing? false
  :new? false
  :respond-with-entity? (fn [{{method :request-method} :request}] (= :put method))
  :put! (fn [ctx]
          (let [old (get ctx ::instance)
                new (update system json-body)]
            (println "###### Old ######\n")
            (clojure.pprint/pprint old)
            (println "###### New ######\n")
            (clojure.pprint/pprint new)
            (assoc ctx ::instance new)))
...
  :handle-ok (fn [ctx]
               (println "####### Result ######")
               (clojure.pprint/pprint (get ctx ::instance))
               (get ctx ::instance)))

=>
###### Old ######

{:children ["51e7e7ab30043ff5187d568e"],
 :_version 2}

###### New ######

{:children ["51e7e7ab30043ff5187d568e" "51e7e7b630043ff5187d5690"],
 :_version 3}

###### Result ######

{:children
 ["51e7e7ab30043ff5187d568e"
  "51e7e7ab30043ff5187d568e" <-- Duplicate!?
  "51e7e7b630043ff5187d5690"],
 :_version 3}

Is this a bug, or am I doing something stupid in my handlers?

Thanks

-Erik

Erik Bakstad

unread,
Jul 18, 2013, 9:35:22 AM7/18/13
to clojure-...@googlegroups.com
I forgot to mention that I don't have the same problem if I assign the result in put! to a new key and return that new key in :handle-ok.

Philipp Meier

unread,
Jul 19, 2013, 6:39:55 AM7/19/13
to clojure-...@googlegroups.com
Hi Erik,
I think you found a bug in the way liberator merges the return value of a decision. Liberator uses the combine function 
a developer to return "{::foo 1}" and liberator updates the context to become {:request {...} :resource {...} :representation {...} ::foo 1}
As you can see a list or vector value will be concatenated to the existing value. I cannot see why this is a sensible
implementation. 

Please fill a bug report asI cannot see a quick work around for you. I suggest that the deep combine logic is replaced with
a top level map merge. As a fallback we can allow decision function to return an function which is applied to the context:

(resource foo 
  :exists? (fn [ctx] (assoc ctx ::foo "bar")) 
  ;; this would not work
  :malformed? (fn [ctx] (dissoc ctx ::foo)))
  ;; this would remove the key
  :malformed? (fn [_] #(dissoc % ::foo)))

On the other hand there is a proposal to allow decision function to return function that will be used
as the next decision in the flow. What I sketched above would collide with this.

-billy.



Erik Bakstad

unread,
Jul 20, 2013, 10:16:30 AM7/20/13
to clojure-...@googlegroups.com
Hi Philipp.

Thanks for looking into it. Create issue: https://github.com/clojure-liberator/liberator/issues/60

Workaround is simply not using the same key, but IMHO it makes sense to keep the semantics of merge.

Cheers

Erik

Philipp Meier

unread,
Nov 7, 2018, 10:08:02 AM11/7/18
to Liberator


Am Donnerstag, 18. Juli 2013 15:31:00 UTC+2 schrieb Erik Bakstad:
Hi. I noticed something strange when storing data in the context re-using the same key. I lookup a value in :allowed? and store it in the ::instance key of the context. If it's a PUT I assoc the result of the update to ::instance and return it in :handle-ok. For some strange reason, this causes a duplication in the vector :children? 

  :put! (fn [ctx]
          (let [old (get ctx ::instance)
                new (update system json-body)]
            (println "###### Old ######\n")
            (clojure.pprint/pprint old)
            (println "###### New ######\n")
            (clojure.pprint/pprint new)
            (assoc ctx ::instance new)))


I think the easies fix is  to use

(fn [ctx]
  ...
  {::instance ^:replace new})

In general avoid returning the full (update) context, especially if you have vectors it it. I'm still thinking about a way to change this without creating regessions in other places.

Philipp Meier

Chris Hapgood

unread,
Nov 27, 2018, 9:18:17 PM11/27/18
to Liberator
I'm pleased to see this project still getting the author's attention.  We use liberator and love it.
Reply all
Reply to author
Forward
0 new messages