3

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 Answers3

2

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

  • Does this work with a parameter in the middle of a route, as in `/environments/:env-name/nodes`? – user2609980 Aug 18 '21 at 15:47
  • I'm not sure. I tried it and the path parameter also become optional. However because the name was different than expected the value was not given to my function. But why would you want this? A path parameter should not be optional. – LetsClojure Aug 18 '21 at 17:07
  • `GET /environments` will give a list of all environments `GET /environments/:env-name` will give you all the details of the environment with name equal to :env-name `GET /environments/:env-name/nodes` will give a list of all nodes within environment :env-name. If you want all nodes of all environments you should define a `GET /nodes` – LetsClojure Aug 18 '21 at 17:13
  • I got the idea of the path parameter in the middle (`/environments/:env-name/nodes`) straight from your question – user2609980 Aug 22 '21 at 16:56
0

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

user2609980
  • 10,264
  • 15
  • 74
  • 143
0

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.

z7sg Ѫ
  • 3,153
  • 1
  • 23
  • 35