Fork me on GitHub
#reitit
<
2022-12-15
>
Jakub Holý (HolyJak)13:12:17

Hi! Regarding https://cljdoc.org/d/metosin/reitit/0.5.18/doc/advanced/dev-workflow#an-easy-fix, how does that work with reitit.ring/ring-handler ? The handler is only constructed once. Thanks!

dharrigan13:12:55

Hi, I created a little gist here

dharrigan13:12:03

that works very very well for me 🙂

ikitommi13:12:43

thanks @U11EL3P9U, having similar utils in projects, SHOULD be part of reitit

dharrigan13:12:56

With that running in my local setup, I can change any route, handler whatever...re-eval the function and things magically just work 🙂

dharrigan13:12:35

(re-eval the handler function, or something that it calls, not the static-ring-handler/reply-friendly-ring-handler...)

ikitommi13:12:44

exactly that. would you like to PR a helper into reitit.ring?

ikitommi13:12:56

also, support both arities, 1 & 3

dharrigan13:12:12

yes, atm, it's all synchronous for me 🙂

ikitommi13:12:32

here’s what I have:

(if dev-mode
  (fn
    ([request] ((create-handler) request))
    ([request respond raise] ((create-handler) request respond raise)))
  (create-handler))

ikitommi13:12:09

maybe a reitit.ring/dev-handler function that takes a 0-arity fn to create the actual ring-handler?

dharrigan13:12:30

letmeseewhatIcanrustleup 🙂

👍 1
❤️ 1
dharrigan13:12:38

I've improved my little demo, seen here to use this way of using the ring-handler.

dharrigan13:12:50

Maybe you might find something useful there 🙂

👀 1
lepistane17:12:36

How does one coerce string to localDatetime using reitit + malli?

{:get {:summary "Gives you link for specific match highlights"
              :parameters {:query [:map
                                   [:match-id uuid?]
                                   [:date [:fn (fn [d] (java.time.LocalDate/parse d))]]]}
              :responses {200 {:body {:link-random string?}}}
              :handler (fn [{{data :query} :parameters}]
                         (prn data)
                         {:status 200
                          :body {:link-random "aa"}})}
}
I am using reitit + malli + swagger example. Why does uuid work but date doesn't?
{:match-id #uuid "2baf6715-b58e-4ec1-b02a-b938bec2cd7d", :date "2022-10-10"}

Ben Sless17:12:29

You need to add a decoder

lepistane17:12:42

(def muuntaja-instance
  (m/create
   (-> m/default-options
      (assoc-in [:formats "application/json" :decoder-opts] {:decode-key-fn csk/->kebab-case-keyword
                                                             ;;<<???>> #(java.time.LocalDate/parse %)
                                                             })
      (assoc-in [:formats "application/json" :encoder-opts] {:encode-key-fn csk/->camelCaseString
                                                             :date-format "yyyy-MM-dd"})


      #_(assoc-in
       [:formats "application/json" :encoder-opts]
       {:date-format "yyyy-MM-dd"}))))
Something like this?

lepistane17:12:48

How do i add decoder?

Ben Sless17:12:11

I really need to get off my ass and write a library to add those

lepistane17:12:29

Yeah i can't figure it out

(malli/coerce :int "invalid" mt/string-transformer)

Syntax error compiling at (src/highlights/server.clj:56:3).
No such var: malli/coerce
I am using malli 0.9.2

Ben Sless17:12:11

Yeah malli has no coerce, you need decode

lepistane17:12:17

(def date-decode (malli/decoder [:fn #(java.time.LocalDate/parse %)] mt/string-transformer))

(date-decode "2022-10-10")

=> "2022-10-10"

Ben Sless17:12:59

That doesn't do what you want it to, hang on I'll whip up a complete example

Ben Sless17:12:45

The malli docs are dense but all the information is there, I just had to read them several times slowly 😞

Ben Sless17:12:33

But you need to understand what schema properties are, how decoders are specified via properties, and how to use them

lepistane17:12:11

Truth is i am using malli for validation in other places. I wanted to reuse same schema.

[:map {:closed true} [:match-id [:fn {:description "Match id", :swagger/default "7e1840af-7758-4baa-957b-cc1bdd753303", :swagger/type "string", :swagger/format "uuid", :error/message "Invalid match-id"} #function[highlights.validation/valid-uuid-as-str?]]] [:date [:fn {:description "Date when the match happened", :swagger/default "2022-10-10", :swagger/type "string", :swagger/format "date", :error/message "Invalid date"} #function[highlights.validation/valid-date-as-str?]]]]
when i failed to make any progress i reduced complexity and failed to do even string -> date conversion.

lepistane17:12:38

i didn't know i had to specify decoders or how to 'plug' them

lepistane17:12:50

Thanks a lot for taking the time to look at this

Ben Sless17:12:34

Fn schemas are evil for this reason, but you can plug decoders into them too

ikitommi17:12:49

(m/coerce
 [:fn
  {:decode/string #(java.time.LocalDate/parse %)
   :decode/json #(java.time.LocalDate/parse %)}
  #(instance? java.time.LocalDate %)]
 "2022-10-10"
 (mt/string-transformer))
; => #object[java.time.LocalDate 0x2bbd77fb "2022-10-10"]

lepistane17:12:18

@U055NJ5CC where is coerce located at? It's not in malli.core?

ikitommi17:12:20

reitit uses m/decode, same results here.

ikitommi17:12:26

coerce thows on error

Ben Sless17:12:01

Can the function returned by coercer have continuation arity, too?

Ben Sless17:12:44

@U45SLGVHV here you go

(require '[malli.core :as m] '[malli.transform :as mt])
(import java.time.LocalDate)

(def local-date
  (m/-simple-schema
   {:pred #(instance? LocalDate %)
    :type-properties
    {:decode/string #(try
                       (LocalDate/parse %)
                       (catch Exception _ %))}}))

(m/decode local-date "2020-10-01" mt/string-transformer)

👍 1
Ben Sless18:12:22

you can add any and all other properties to the type-properties map

lepistane18:12:15

Oh little bit of cheating, i thought i was going mad because i couldn't find it my v0.9.2 of malli Thanks a lot. Basically adding

[:fn
  {:decode/string #(java.time.LocalDate/parse %)
   :decode/json #(java.time.LocalDate/parse %)}
  #(instance? java.time.LocalDate %)]
to existing schema solved it

lepistane18:12:36

@UK0810AQ2 thanks for this but how does it differ from the above?

ikitommi18:12:49

maybe we should finish adding the https://github.com/metosin/malli/pull/545 to malli, copy-pasting what is needed between projects :thinking_face:

Ben Sless18:12:56

we can start adding properties, such as the expected pattern, min and max date, those are for specific instances of the schema. Additionally we could add more things to the schema, put it in a registry, and make it less opaque

👍 1
Ben Sless18:12:34

I learned some stuff since then wrt time schemas, I can do it better now

Ben Sless18:12:44

they should all be able to take properties

ikitommi18:12:26

want to finish the draft?

Ben Sless18:12:42

I'll open a new MR

👍 1
lepistane19:12:13

@U055NJ5CC @UK0810AQ2 why am i allowed to make wrong input in swagger and input doesn't get to be red? also if i try execute it fails on the server. If i change uuid to something bad it doesn't even allow me to 'execute'

lepistane19:12:17

what is different between

[:map {:closed true} [:match-id [:fn {:description "Match id", :swagger/default "7e1840af-7758-4baa-957b-cc1bdd753303", :error/message "Invalid match-id"} #function[clojure.core/uuid?]]]]
and just putting
[:map [:match-id uuid?]]
Second one makes swagger behave how i expect it. If i put values in input that are not uuid i can't even execute the request. Is there a way for me to make a custom schema that behaves the same way native one does? With input validation and all?

Ben Sless19:12:36

What matters isn't the predicate function, but how it's externalized over json schema to the swagger UI

lepistane19:12:47

Thanks i get that but i found weird behaviors. I've been on this whole day so maybe fatigue is taking it's toll. I will step out and try again tomorrow Thanks both for your time and effort

lepistane07:12:47

I think i figured it out for date 🙂 You were right i had to look on how description was done in swagger.

[:fn {:swagger/description "Date when the match happened"
               :swagger/default "2022-10-10"
               :swagger/type "string"
               :swagger/format "date"
               :swagger/pattern #"^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$"
               :decode/string #(java.time.LocalDate/parse %)
               :decode/json #(java.time.LocalDate/parse %)
               :error/message "Invalid date"}
          date?]
working example on how to have input validation in swagger for others. Pattern is needed to have full control over date format type string.

lepistane07:12:09

Regarding UUID it seems to be that as soon as you put [:fn... in your schema you need to provide decoders and helpful defaults are out. So you need to specify all json-schema goodies you need.

lepistane07:12:20

Thanks for pointing me out to right direction!

ikitommi09:12:18

👍 related to :fn - it has no type so you have to tell everything yourself. There is an old issue of type-tagging schemas easily, which would allow you to say: [:fn {:type :int} (fn [x] …]] and all schema applications (transforming, generators, json-schema, …) would know it’s an :int.

ikitommi09:12:35

plan is to work on that early next year.

👍 1
lepistane19:12:17

what is different between

[:map {:closed true} [:match-id [:fn {:description "Match id", :swagger/default "7e1840af-7758-4baa-957b-cc1bdd753303", :error/message "Invalid match-id"} #function[clojure.core/uuid?]]]]
and just putting
[:map [:match-id uuid?]]
Second one makes swagger behave how i expect it. If i put values in input that are not uuid i can't even execute the request. Is there a way for me to make a custom schema that behaves the same way native one does? With input validation and all?

Martynas Maciulevičius19:12:49

Hey. Is it possible to somehow reload routes without restarting the whole server? I'm thinking whether I can have a running websocket but then reload some REST routes :thinking_face:

Martynas Maciulevičius20:12:50

#'app binding might work for me :thinking_face:

Martynas Maciulevičius20:12:30

Ah, that's quite neat 😄 Thanks!

dharrigan21:12:08

I'm updating my example (on github) to use this

dharrigan21:12:45

with added bonus of malli validation 🙂

dharrigan22:12:34

Here you go:

dharrigan22:12:56

A major update. Includes malli validation, tests, transactions, reloadable routes...

dharrigan22:12:20

rollbackable transactions during testing...

dharrigan22:12:27

I'm tired now. I go to bed 🙂

dharrigan13:12:39

Updated with generators and more tests!