Fork me on GitHub
#reitit
<
2019-06-04
>
RafaMedina00:06:22

Hi all Question: I know the responses (swagger) are written like this: :responses {200 {:body {:total string?}}} I'd like to know how to specify multiple responses for the same endpoint, ex. when the request returns another status, for example, 401

ikitommi05:06:05

@comparalf just add a new response code under :responses, e.g. {200 ..., 401 ...}

ikitommi05:06:50

only thing that spec-tools & schema-tools do there is to convert the :body definition into Swagger :schema

ikitommi05:06:08

otherwise, everything is passed directly to api-docs

ikitommi05:06:04

@stefan.age sorry, no docs, but . Would be great to have a tutorial for the frontend. the there is a sample in https://github.com/metosin/reitit/tree/master/examples/frontend-links

ikitommi09:06:28

not directly related to reitit, but building a wrapper for reactive / non-blocking sql client for clojure, will work oob with reitit-http thanks to sieppari, uses vertx-sql-client under the hoods:

(require '[porsas.async :as pa])
(require '[promesa.core :as p])

(def pool
  (pa/pool
    {:uri ""
     :user "benchmarkdbuser"
     :password "benchmarkdbpass"}))

(def mapper (pa/data-mapper))

(-> (pa/query-one mapper pool ["SELECT randomnumber from WORLD where id=$1" 1])
    (p/chain :randomnumber inc inc)
    (p/bind println))
; => #<Promise[~]>
; prints 2839

mitchelkuijpers13:06:05

Hi when using reitit-pedestal I found something that seems incorrect the routing interceptor from reitit-http matches on :uri but the normal pedestal router matches on :path-info. This only hits me because we are adding pedestal to a servlet and trying out reitit. But our servlet has a context path for our case it's /jira

mitchelkuijpers13:06:38

So this would mean I would need to add /jira to all of my routes, but this could be anything because it is configurable

mitchelkuijpers13:06:09

I fixed it by creating an interceptor for pedestal:

(def fix-reitit-matching
  (io.pedestal.interceptor/interceptor
   {:name ::fix-reitit-matching
    :enter (fn [context]
             (assoc-in context [:request :uri] (get-in context [:request :path-info])))}))

ikitommi13:06:57

yes, there is nothing for servlets for now. I guess the swagger-docs are also off because of that.

ikitommi13:06:25

curious, what is the use case for using servlets vs standalone jar?

ikitommi13:06:58

haven’t used them in years, but remember the same uri patching done in compojure-api & ring-swagger.

mitchelkuijpers13:06:31

Basically constraints, we are writing a JIRA addon with clojure. And you have the possibility to mount servlets from addons

mitchelkuijpers13:06:29

So we create a big jar and Jira loads it and parses some xml and voila we get mounted under a certain servlet path

mitchelkuijpers13:06:10

Swagger was my next step, but you don't think that that is possible?

mitchelkuijpers13:06:14

btw this is exactly what happens:

:path-info "/plugins/servlet/atlascrm/api/contact/1",
:context-path "/jira",
:uri "/jira/plugins/servlet/atlascrm/api/contact/1",

mitchelkuijpers13:06:41

Btw we are not married to Pedestal, so if I could do this some other way we would also be interested

mitchelkuijpers13:06:36

Ah I see we could also look at ring-servlet, not sure if pedestal is worth the trouble for our use case

RafaMedina13:06:58

Thank you @ikitommi, I had an extra {200 fncall} around the response too

ikitommi13:06:06

@mitchelkuijpers do you need to strip out the :context-path from :uri or add that in? in the example :uri has it, but :path-info doesn’t

ikitommi13:06:33

for swagger, there is route data {:swagger {:basePath "/jira"}} which indicates that /jira need to be concatenated to all paths.

mitchelkuijpers13:06:49

I need to strip it out when matching

ikitommi13:06:46

what about reverse-routing? do you need to add it back?

mitchelkuijpers13:06:11

Yes pedestal did that for us

ikitommi13:06:12

if you know the context at router creation time, it would be easy just to add the :path option to router, e.g:

(-> (r/router
      ["/kikka"]
      {:path "/jira"})
    (r/routes))
;=> [["/jira/kikka" {}]]

ikitommi13:06:16

if that’s dynamic, you need to do the runtime uri-conversion (as you have) and hint both the swagger-ui & reverse-routing to do the same in reverse.

mitchelkuijpers13:06:11

Ah yeah it could be dynamic, you can expose them on a context path and on another one

mitchelkuijpers13:06:58

I think I am also going to look at ring-servlet, it seems reitit does mostly everything that pedestal does but better documented

mitchelkuijpers13:06:17

Then I'll rather have a real easy layer inbetween

ikitommi13:06:11

thanks. no docs are perfect, feel free to contribute if something is missing.

mitchelkuijpers13:06:50

Sure, thank you for listening

mitchelkuijpers14:06:59

Nice, it works way simpler with ring-servlet

mitchelkuijpers14:06:46

Btw in ring I get: servlet-context-path "/jira" so I think it should be possible to create some simple helpers

👍 4
mitchelkuijpers14:06:56

Now we are running into fun situations with for example (ring/redirect-trailing-slash-handler)

mitchelkuijpers14:06:31

Would you accept some sort of PR for adding a concept of context or something along the lines?

ikitommi15:06:35

@mitchelkuijpers sure thing, maybe start with a quick draft first to see all the places it effects? and a zero perf penalty for cases it’s not used.

mitchelkuijpers15:06:35

Good one, will take a while will first work around it, I have some deadlines, maybe it is solvable with some small helpers around

mitchelkuijpers15:06:57

For example I could copy the redirect-trailing-slash-handler for now

mitchelkuijpers15:06:30

I can imagine this simply not being a very interesting case for some folks

ikitommi15:06:16

think so too, not many servlet-based apps out there, compared to standalone apps.

mitchelkuijpers15:06:34

Yeah, but we are very happy that it is possible

mitchelkuijpers15:06:49

Otherwise we would be doing Java and Spring

ikitommi15:06:47

sure, I think the changes will be subtle, most likely an new option into reitit.ring/ring-handler or reitit.ring/router.

ikitommi15:06:32

+ some code reading it in few places. could you write an issue out of that so people can find it later?

mafcocinco16:06:43

My company is considering adopting reitit (switching off of Compojure). In playing around with the lib, we were having difficulty getting query parameter data to show up when matching on path. Basically something like /foo would would match correctly. However /foo?hello=world would return nil when attempting to match. I'm guessing that we need to include additional data during route creation but I was not able to find any examples of this in the documentation.

ikitommi16:06:02

@mafcocinco welcome! ring specifies the :uri not to contain the query-string, which should be separately in the :query-string. All the ring-adapters I know do this. Where do you get that uri?

ikitommi16:06:03

correct request would be {:uri "/foo", :query-string "hello=world"}

mafcocinco17:06:06

Just calling match-by-path in the REPL. So it seems reitit expects the URI that ring produces, i.e. already parsed with query params removed.

ikitommi17:06:58

yes, it does.

mafcocinco17:06:10

roger. Thank you for your help.

mafcocinco17:06:39

One followup and this could just be my ignorance of frontend development: How does this work in the context of a re-frame or other CLJS application? AFAIK, Ring is a server side library but reitit can be used for front end routing (and we are planning to use it from both FE and BE). Is this the point of the reitit.frontend.* namespaces?

ikitommi17:06:23

yes, the reitit-frontend should be idiomatic with js/cljs, while reitit-ring is with ring. Frontend doesn't have as much docs but hopefully the examples help

RafaMedina18:06:34

@mafcocinco maybe this could help you to figure out the way.. (it's based in the example) it's kind a short summary haaha it's with re-frame

(def pages
  {:login [login-page]
   :main [main-page]})

(def router
  (reitit/router
   [["/" :main]
    ["/login" :login]
]))

(defn main-layout []
  (r/with-let [active-page (subscribe [:active-page])
               user (subscribe [:user])]
    [:div
     (if @user
       [:div
        (pages @active-page user)]
       (pages :login nil))
     [:pre (with-out-str (fedn/pprint user))]]))
the hook-browser-navigation! very important

stefan18:06:01

Using the above setup, any idea why /graphiql or /foobar always renders the home component?

RafaMedina18:06:03

when you don't have an idea what is clojure, the most simplest thing takes a long time haahaha