clojurecompojureluminuscompojure-api

Compojure-api removes body-param after the first group of API routes


I am currently using the Luminus template with the +swagger option, which adds compojure-api support.

My current setup is like so (only relevant bits):

(ns my-project.routes.services
  (:require [compojure.api.sweet :refer :all]
            ,,,)

(defapi service-routes
  (POST "/login" req
    :return Result
    :body [user UserLogin]
    :summary "Log the user in"
    (auth/login! req user))

(defapi restricted-service-routes
  (POST "/login2" req
    :return Result
    :body [user UserLogin]
    :summary "Log the user in"
    (auth/login! req user)))

and

 (ns my-project.handler)
   (:require [my-project.routes.services :refer :all])

 (defroutes app-routes
     #'service-routes
     #'restricted-service-routes)

When the server receives the request, it is passed to app-routes. I then used the Swagger UI to test these routes, and the "/login" route worked fine. However, the completely similar "/login2" returns

{
  "errors": "(not (map? nil))"
}

When I switch the order of the two service groups, the result is as expected: the first route works fine, while the second will not receive the body.

Is this a bug with Compojure-api itself? And is there anything I can do to work around this?


Solution

  • defapi macro seems to wrap all the routes to api-middleware (check out compojure-api source code) which includes wrap-params middleware. In your setup, you are chaining two set of routes both wrapped in the api-middleware and thus calling the wrap-params middleware on a request in case of the second defapi route (/login2) twice. The first call of wrap-params resolves the params correctly but the second wrap-params call has nothing to process and thus your code ends up with runtime error.

    To solve your issue, try to disable default wrapping by api-middleware for all your defapi usages but one. See the :disable-api-middleware option in the link above.