In designing our (by now) two clojure-based REST services we are struggling 
with managing flow-control.

(Disclaimer: earlier backgrounds are with Python, C, Javascript and once 
upon a time Java/C# etc)

What we'd like is to accomplish a series of steps which we feel are 
universal to REST-services.
In the context of PUT/POST that is:
---
1. ensure that the content is of a given format (application/json)

2. receive & validate input
2a. if the input is invalid, return error output (in our case describing 
what went wrong)

3. create a new entry / update an existing entry
(Note if you know the entire URI, then using PUT for both updating/creating 
is acceptable)

4. format a response (typically containing the created/updated object)
---

Fig1 details how, after several passes, we're dealing with this. The 
approach is heavily inspired
by Ref1 and essentially executes each step outlined above with the 
understanding that failure might
occur. If a failure occurs, an error message is returned (of course).

We chose an approach similar to Ref1 because we wanted to abort on errors, 
occasionally recover
(such as update becoming create if no record is found) and we wanted 
detailed errors which
precludes the use of (and ...).

The astute observer may note that our model fails to capture the concept of 
recoverable failures
- update-record* may fail for more reasons than simply not having a row 
(transient errors, actual
logic-related errors etc) some of which are non-recoverable. 

As it stands, this means the function needs refactoring, *again*. 
What all this boils down to is this: given the unique interplay of 
immutability with LISP-style
(AST) syntax - which techniques are successfully employed to avoid heavily 
indented code ? Is
the only solution really to either:

1) decompose functions into smaller functions, regardless of
these helper functions being of no use anywhere else.

2) define a bunch of helper functions in a top-level let-expression - again 
to avoid having
   functions which are too heavily indented?


Does it ever get easier ? Are we missing something ? It seems extreme to 
reach for monads for
something of this nature.

References
1. https://brehaut.net/blog/2011/error_monads (Ref1)

Fig. 1. - a PUT endpoint
------------------------
(defn update*
  "create/update a pin."
  [cid source rq]
  (err/attempt-all
   [_ (chk/mediatype-in? (get rq :content-type) ["application/json"])
    rq (clojure.walk/keywordize-keys rq)
    ;; data which can come from the user
    input (merge {:method "app"
                  :seen_at (-> (at/now-utc) (at/->dt-utc-str))}
                 (get rq :body)
                 {:source_type (get source :type) :source_id (get source :id
)})
    _ (av/input-valid? validate-pin-params input)


    ;; additional data extracted from URI & token
    record-data (merge input
                       {:cid cid
                        :uid (rq->uid* rq)})
    record (err/any (update-record* record-data)
                    (new-record* record-data))]
   ;; Success
   (rsp/created
    (url cid source)
    {:key-name "pinid"
     :body {:request (model/transform record)}})
   ;; Failure
   err/handle-failure))

------------------------

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to