Fork me on GitHub
#reitit
<
2019-06-20
>
johnnyillinois05:06:11

Anyone know how to define a custom spec transformations using the built in reitit coercion middleware?

johnnyillinois05:06:30

For example, if I want to define how to encode and decode a custom type

johnnyillinois05:06:57

like:

(s/def ::created-at
    (st/spec
     {:spec (s/spec :clj-time.spec/date-time)
      :swagger/type "string"
      :swagger/format "date-time"
      :decode/string (fn [_ y]
                       (clj-time.coerce/to-string y))
      :encode/string clj-time.coerce/from-string}))

johnnyillinois05:06:28

^ this doesn't work as expected

ikitommi05:06:35

@johnnyillinois encode should also be 2-arity fn:

(require '[clojure.spec.alpha :as s])
(require '[spec-tools.core :as st])

(def spec
  (st/spec
    {:spec (s/and int? #(> % 10))
     :swagger/type "integer"
     :decode/string (fn [_ y]
                      (Long/parseLong y))
     :encode/string (fn [_ y]
                      (str y))}))

(as-> "11" $
      (doto $ prn)
      (st/decode spec $ st/string-transformer)
      (doto $ prn)
      (st/encode spec $ st/string-transformer)
      (doto $ prn))
; "11"
; 11
; => "11"

johnnyillinois05:06:20

I agree! After looking at the stacktrace, I don't think the encoder is called. But I will try now

johnnyillinois05:06:03

That works!

(def my-spec
    (st/spec
     {:spec (s/and int? #(> % 10))
      :swagger/type "integer"
      :decode/string (fn [_ y]
                       (println y)
                       y)
      :encode/string (fn [_ y]
                       (str y))}))

  (def test-router
    (r/router
     ["/:created-at" {:name ::user-view
                                  :coercion reitit.coercion.spec/coercion
                                  :parameters {:path {:created-at my-spec}}}]
     {:compile coercion/compile-request-coercers}))

  (def x (r/match-by-path test-router "/11"))
  (def q (coercion/coerce! x))
  (do q) => {:path {:created-at 11}}

johnnyillinois05:06:19

Thank you. I see you are replying to the issue. I'll put the documentation on github

👍 4
ikitommi06:06:43

Btw, heading for 5 week vacation starting tomorrow, and in July mostly out of internet.

👍 8
🙌 4
Toni Vanhala06:06:34

Highly recommend the five-week Finnish summer vacation for everyone. After that you can join us at #clojutre to meet&greet @ikitommi. 😄 https://clojutre.org/2019/

🌴 4
ikitommi06:06:46

There seems to be a bunch of frontend PR’s almost finished, would be nice to cut a release of those.

Toni Vanhala06:06:34

Highly recommend the five-week Finnish summer vacation for everyone. After that you can join us at #clojutre to meet&greet @ikitommi. 😄 https://clojutre.org/2019/

🌴 4
abdullahibra10:06:49

in this example: https://github.com/metosin/reitit/blob/master/examples/frontend-auth/src/frontend/core.cljs it saves the state of logged user to state atom, how can i replace this state atom to save it to re-frame db, and how can query the re-frame db, using subscriber ?

abdullahibra10:06:27

so i should create subs to check the value of user in re-frame db, and add @(rf/subscribe [::user]) rather than state ?, subscriber should be added to re-renderable components?

manutter5111:06:31

Yes, it’s very straightforward, just change the :on-change handlers to use #(rf/dispatch [:user-form/edit-password %]) (for example), and then use a subscription to get the value instead of getting it from @form.

abdullahibra10:06:38

also i have another question, if i have multi role users like admin, normal user, how can i authenticate both using controller?, what is the best way to extend the code in page i mentioned above?

manutter5111:06:32

We have a controller that looks like this:

(def require-auth-controller
  {:start (fn [m]
            ;; If not logged in, go to :login, then return to original destination
            (rf/dispatch [:nav/ensure-login (get-in m [:data :name])]))})
The :nav/ensure-login handler checks whether we have a value for :current-user (which is only filled in for logged-in users), and dispatches a :nav/login-required event if not.
(rf/reg-event-fx
  :nav/ensure-login
  (fn-traced [{:keys [db]} [_ page]]
    (let [user (:current-user db)]
      (if (empty? user)
        {:dispatch [:nav/login-required page]}))))
Note that we’re passing the original page through to the “login required” handler so we can return to the original page after login. The :nav/login-required handler stores the original page in the app-db, and then redirects to the login page. So if the user tries to go to a page that requires a login, they will immediately be redirected to the login screen if they’re not already logged in.

manutter5111:06:57

After logging in, the “login success” handler checks the app-db for a :return-to-page value, and if it’s not null, it redirects the user back to the original page.

abdullahibra10:06:00

also how can i navigate the page without using rfe/href ?

manutter5112:06:06

The rfe/href should work fine, but you can just as easily dispatch something like a :nav/go-to-page event. Ours looks like this:

(rf/reg-event-fx
  :nav/go-to-page
  (fn-traced [_ [_ page]]
    (rfe/push-state page)))
and you call it like this (rf/dispatch [:nav/go-to-page :dashboard]).

☝️ 4
abdullahibra13:06:28

guys how do you use re-frame app-db with reitit state atom ?