How to define an optional query parameter with reitit clojure

1.3k views Asked by At

I created an API using the following code:

   ["/environments/:env-name/nodes"
    {:swagger {:tags ["Nodes"]}
     :parameters {:path {:env-name ::vt-vali/name}}}
    [""
     {:get {:summary "Retrieve the nodes from this environment"
            :parameters {:query {:date ::vt-vali/timestamp}}
            :responses {200 {:body map?}}
            :handler (fn [{{{:keys [env-name]} :path
                            {:keys [date]} :query} :parameters}]
                       (let [result (vt-data/ret-nodes env-name date)]
                         (if (s/valid? map? result)
                           {:status 200
                            :body result}
                           {:status 500
                            :body result})))}}]]

This works perfectly. However, I want to make the query parameter optional.

Can anyone help me with this?

3

There are 3 answers

4
LetsClojure On

I found an answer by searching through the examples in metosin/reitit.

It is possible to use clojure.spec.alpha. Add [clojure.spec.alpha :as s] to the required dependencies of the namespace and you can use:

:parameters {:query (s/keys :opt-un [::date])}

See this file for the example in metosin/reitit http-swagger example

0
user2609980 On

I don't think that can be done. You can add an extra route:

(defn handler [{{{:keys [env-name]} :path
                 {:keys [date]} :query} :parameters}]
  (let [result (vt-data/ret-nodes env-name date)]
    (if (s/valid? map? result)
      {:status 200
       :body result}
      {:status 500
       :body result})))

["/environments/nodes"
 {:swagger {:tags ["Nodes"]}
  :parameters {:path {:env-name ::vt-vali/name}}}
 [""
  {:get {:summary "Retrieve the nodes from this environment"
         :parameters {:query {:date ::vt-vali/timestamp}}
         :responses {200 {:body map?}}
         :handler handler}}]
 "/environments/:env-name/nodes"
 {:swagger {:tags ["Nodes"]}
  :parameters {:path {:env-name ::vt-vali/name}}}
 [""
  {:get {:summary "Retrieve the nodes from this environment"
         :parameters {:query {:date ::vt-vali/timestamp}}
         :responses {200 {:body map?}}
         :handler handler}}]]

0
z7sg Ѫ On

It is possible but the implementation depends on what type of coercion you are using. In Reitit, routing and coercion are separate concerns, see here for a detailed explanation. It's not possible for path elements because they are part of the route.

There is already an answer that describes optional parameters clojure.spec coercion. If you are using malli coercion instead, an optional query parameter could look like this:

["/hello" {:get {:parameters {:query [:map [:a {:optional true} int?]
                                           [:b int?]]}}
                 :responses {200 {:body [:map [:total pos-int?]]}}
                 :handler handler}}]

For more info, read the malli documentation.