LetsClojure
LetsClojure

Reputation: 135

How to define an optional query parameter with reitit clojure

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?

Upvotes: 5

Views: 1651

Answers (3)

z7sg Ѫ
z7sg Ѫ

Reputation: 3213

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.

Upvotes: 2

LetsClojure
LetsClojure

Reputation: 135

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

Upvotes: 4

user2609980
user2609980

Reputation: 10504

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}}]]

Upvotes: 0

Related Questions