Optional query parameters (with default value) with compojure-api
Asked Answered
W

2

14

What is the proper way to declare an optional query parameter, with default value, when using compojure-api?

One of my route elements is as follows (after reading this):

(GET "/:id/descendants" [id]
     :return [d/CategoryTreeElement]
     :path-params [id :- Long]
     :query-params [context-type :- d/ContextType
                    levels :- Integer
                    {tenant :- d/Tenant :DEF_TENANT}
                    {show-future :- Boolean false}
                    {show-expired :- Boolean false}
                    {show-suppressed :- Boolean false}
     :summary "Fetch category descendants"
     (ok ...))

At first the boolean params where defined as the other ones (e.g. show-future Boolean) but the generated Swagger UI presented them as a combobox with true value as default. In the present form the UI shows a combobox with no option selected. The same happens with tenant.

One side question: when I use Swagger generated UI to send a request and error is returned: "levels": "(not (instance? java.lang.Integer \"2\"))". Why is that? Isn't the library supposed to coerce/convert string values to the designated types declared by the API?

Thanks in advance.

Waterhouse answered 7/3, 2016 at 18:14 Comment(0)
E
5

For your first issue, this is working as designed. When you had your boolean query param required, Swagger rendered the UI which forces you to choose a value (either true or false, it just happens that it displays true on the first place).

When you changed the boolean query param to be optional, then the first empty value means "don't send this query param at all" and when you don't change it to true or false it won't append this query param to the request.

Regarding your second issue with integer query param: by default schema's json-coercion-matcher specifies String->Long coercion but not String->Integer so there is no support for Integer out of the box. You can specify your own coercer globally for your API or per route by using :coercion option (there is an example in compojure-api test). You could provide your own coercer which could extend the existing json-coercion-matcher with String->Integer case.

Environ answered 7/3, 2016 at 18:37 Comment(4)
Thanks for you answer. So about the boolean optional parameter, it does not matter if I define a default value, since the default value is not selected on the UI.Waterhouse
@matheus.emm You do have to specify the default parameter value if you want it to be optional. Otherwise Swagger UI will force you to choose one of the values (true or false) and if you send the request without specifying a value for that query parameter you will get schema validation error. Default value is required so your parameter has a valid value assigned (according to your schema) if it's not provided by the caller.Environ
@matheus.emm I have updated the answer with the info how to handle Integer coercion.Environ
Nice! Thanks very much!Waterhouse
H
0

If you use clojure.spec and you want as a default value false in your swagger documentation for a boolean variable you can use spec tool library and do something like :

(s/def ::show-future 
  (st/spec {:spec boolean?
            :json-schema/example false
            :json-schema/default false}))

Then, in your query params :

:query-params [{show-future :- ::show-future false}]
Hines answered 15/4, 2019 at 15:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.