compojure-api return value schema or error

745 views Asked by At

compojure-api allows you to define the return schema:

(s/defschema Pizza
  {:name s/Str})

(GET "/pizza/:id" [id]
  :return Pizza
  :summary "returns a Pizza"
  (ok (get-pizza id)))

My issue is when the get-pizza fn returns a 404 {:status 404 :body {:message "Invalid id provided"}} the response (to the requester) is that that 404 does not match the Pizza schema:

{
  "errors": {
    "name": "missing-required-key",
    "status": "disallowed-key",
    "body": "disallowed-key"
  }
}

The docs show that you can provide multiple response schemas but I am unclear on what my get-pizza fn should return in order to utilize those schemas. Their example uses the ring-http-response lib to generate the return values, but there is no difference between my return value for get-pizza and the ring-http-response 'not found' fn.

Truthfully I would rather not use the :responses param if possible because I can already foresee all the code duplication. Before specifying the :return Schema I was able to have my get-pizza fn return a 404 and be correctly passed onto the requester but once I added the Schema I was no longer able to do that. I considered having the return value be :return (s/one Pizza Error) where Error would be a generically defined error map but I don't see why I would do this for every route if all calls could in theory return a 500.

Note: The reason I switched to utilizing the :return param is that it makes the generated swagger-ui docs much prettier & easier to understand.

1

There are 1 answers

5
Piotrek Bzdyl On

You have a small issue in your code I assume as you didn't show implementation of your get-pizza [id] function.

You return {:status 404 :body {:message "Invalid ID provided}} which is then wrapped into HTTP 200 response by (ok (get-pizza id)).

Your get-pizza function should return a pizza or nil if not found. Your HTTP response should be generated based on that in your route:

(GET "/:id" []
  :path-params [id :- Long]
  :return Pizza
  :summary "Gets a pizza"
  (if-let [pizza (get-pizza id)]
    (ok pizza)
    (not-found {:message "Invalid ID provided"})))

The original example from compojure-api repo has a bit different implementation where for nil values from get-pizza it will still return HTTP 200 response with empty response body. According to your question you would return 404 instead and the code above should meet your requirement.