Fork me on GitHub
#reitit
<
2022-01-25
>
dharrigan16:01:45

I'm wondering, in compojure sweet, the predessor to reitit, it had this functionality of meta/restructure-param which allowed one to register a multimethod value, that was handled by compojure sweet (detailed here: https://github.com/metosin/compojure-api/wiki/Creating-your-own-metadata-handlers). What would be the approach if one was moving to reitit from compojure sweet and the legacy system had loads of these. What comes to mind is simply to add to the response (on the way out) a key/value pair and have some middleware look for that key/value pair and handle accordingly.

juhoteperi16:01:36

Compiled middleware can be used to attach middleware to specfici routes based on route-data: https://cljdoc.org/d/metosin/reitit/0.5.15/doc/ring/compiling-middleware

dharrigan16:01:05

Thank you, reading.

dharrigan16:01:10

I see I see, cool, thank you.

dharrigan16:01:22

Perhaps there might be a better migration route?

jussi16:01:45

If I want to unit test my reitit routes with malli validation, how should the body be submitted? Despite how I submit the body contents I get coercion error. I've tried plain data as in nclj maps, json and even InputStream to no avail.. Feeling quite stupid at the moment 🙈 Error

ERROR in () (coercion.cljc:46)
Claim
expected: (= {:status 200, :body {}} (app (request "/api/claim" :put valid-json-claim)))
  actual: clojure.lang.ExceptionInfo: Request coercion failed: #reitit.coercion.CoercionError (full schema here)
.
.
.
:errors (#Error{:path [], :in [], :schema [:map {:closed true} (schema continues...)
Route conf
["/claim"
     {:put {:parameters {:body schema/claim}
            :responses {200 {:body string?}}
            :handler (fn [{:keys [body-params]}]
                       (log/info (str "Got body" (:body body-params)))
                       {:status 200
                        :body (:body body-params)})}}]
Reitit conf
(def app
  (ring/ring-handler
   (ring/router
    (routes)
    {:data {:muuntaja muuntaja/instance
            :middleware [#_wrap-internal-error
                         swagger/swagger-feature
                         middleware.muuntaja/format-negotiate-middleware
                         middleware.muuntaja/format-response-middleware
                         middleware.muuntaja/format-request-middleware
                         wrap-dbg
                         #_coercion/coerce-exceptions-middleware
                         coercion/coerce-request-middleware
                         coercion/coerce-response-middleware]
            :coercion (reitit.coercion.malli/create
                       {;; set of keys to include in error messages
                        :error-keys #{:value :humanized #_:type :coercion :in :schema :errors  #_:transformed}
                        ;; validate request & response
                        :validate true
                        ;; top-level short-circuit to disable request & response coercion
                        :enabled true
                        ;; strip-extra-keys (effects only predefined transformers)
                        :strip-extra-keys false
                        ;; add/set default values
                        :default-values true
                        ;; malli options
                        :options nil})}})

   (ring/routes
    (swagger-ui/create-swagger-ui-handler
     {:path "/"
      :config {:validatorUrl nil
               :operationsSorter "alpha"}})
    (ring/create-default-handler))))
Test, where valid-json-claim is a map turned into json with jsonista
(defn- request
  ([uri method]
   (request uri method nil))
  ([uri method body]
   {:uri uri
    :request-method method
    :body body}))

(deftest routes-test
  (testing "Routes"
    (testing "Claim"
      (is (= {:status 200 :body {}}
             (app (request "/api/claim" :put valid-json-claim)))))))

jussi16:01:27

Do I actually need to use ring-mock?

jussi17:01:56

Hmm, or just :body -> :body-params :thinking_face:

jussi17:01:05

Yeah, that it was picard-facepalm Serious case of PEBKAC but thank you for being my rubber duck duckie

iGEL17:01:46

Hello! Can route params be optional? I want to route "/messages" and "/messages/123" to the same handler. Rails allows routes like "/messages(/:id)", is that possible?

jussi17:01:37

There are catch-all-parameters indeed ➡️ https://github.com/metosin/reitit/blob/master/doc/basics/route_syntax.md Route with catch-all parameter:

["/public/*path"]

lgessler23:01:34

hi, could somebody help me understand what's wrong with my params declaration? I have a :get, and I want a query param param to be foo, bar, or nothing. My parameters map is {:query {:param (ds/maybe (s/spec #{"foo" "bar"}))}}. My handler correctly rejects any non-empty param value that's not "foo" or "bar" but incorrectly rejects a request that doesn't specify any value for param