Fork me on GitHub
#ring-swagger
<
2017-04-11
>
kasuko13:04:32

Hey guys, I am experience an incredibly frustrating issue. We are attempting to add compojure-api to our application to manage our api endpoint. For our api-endpoint everything is doing GREAT! However, for other endpoints on our app we’re still using plain compojure. One of those endpoints expects transit+json in the body and it is getting nothing. I have since mocked the InputStream in the body to one that will log every read from it and I found out that the body is being read in the ring.middleware.format-params middleware which is being applied by the compojure-api.

kasuko13:04:59

So my question is, is there a way to have the compojure-api middleware be applied ONLY to the compojure-api routes?

juhoteperi14:04:26

@kasuko No. It is impossible for the middleware to know if route will be matched so it has to read the body always.

juhoteperi14:04:27

It is possible to work around this if all your Compojure-apis are under some prefix like /api, then you can mount Compojure-api handler under context

juhoteperi14:04:58

but if your top-level handler is something like (or (compojure-api req) (normal-compojure req)) the Compojure-api middleware will run always

juhoteperi14:04:38

I'd recommend just porting all the endpoints to Compojure-api, changing the requires from compojure to compojure.api should be enough

kasuko14:04:41

Yes our compojure-api routes are all under the /api prefix

kasuko14:04:28

As for converting them all the compojure-api, we don’t really want to schema our other endpoints right now

juhoteperi14:04:37

compojure-api doesn't require schema

juhoteperi14:04:59

everything that works in compojure, should work the same in compojure-api

kasuko14:04:43

Alright I will give that a try

kasuko16:04:52

@juhoteperi Nope, I switched the route to be a compojure-api route and the middleware is still destroying the body of the request

juhoteperi16:04:03

@kasuko I don't quite understand what you are doing

juhoteperi16:04:21

Is defapi or api your top level handler or not?

juhoteperi16:04:35

Is it directly under context?

kasuko16:04:42

We are using the system component library for managing our endpoints and handler

kasuko16:04:53

so we have

kasuko16:04:11

:api-endpoint (system.endpoint/new-endpoint (fn [_] handler/app-api))

   :app-endpoint (component/using (system.endpoint/new-endpoint (fn [_] handler/app-routes))
                                  [:api-endpoint])

kasuko16:04:44

where handler/app-api is pretty much just

(def app-api
  (api/api {...}
   (api/context "/api" []
                (api/middleware
                 [[auth/wrap-authorize #{"user"}]]
                 (api/context "/search" []
                              :tags ["search"]
                              search.handler/routes)
                 (api/context "/reports" []
                              :tags ["reports"]
                              reports.handler/routes)
                 (api/context "/dashboard" []
                              :tags ["dashboard"]
                              dashboard.handler/routes)))))

juhoteperi16:04:59

@kasuko you should not have both api/api and api/middleware

juhoteperi16:04:49

right its compjure.api.core/middleware

juhoteperi16:04:06

this is not going to work

juhoteperi16:04:22

what does merge those two endpoints?

juhoteperi16:04:43

oh right, app-endpoint uses api-endpoint

juhoteperi16:04:08

you app-endpoint should have context "/api" and api-endpoint shouldn't have that

juhoteperi16:04:36

your app-routes probably does something like (routes api-routes (GET "/index.html" ...) what-ever)

juhoteperi16:04:55

which means that all the middleware in api-routes is always run

kasuko16:04:32

Ya our app-routes are just for the SPA

kasuko16:04:51

(defroutes app-routes
  (GET "/" req (fn [& _] (index)))...)

juhoteperi16:04:54

doesn't app-routes use api-endpoint? why does that component use :api-endpoint?

kasuko16:04:39

Whoops, sorry ya I was simplifying and forgot I was. The actual issue is with a 3rd endpoint for client performance statistics gathering :S

kasuko16:04:31

It’s routes are

(defroutes client-perf-routes
  (POST "/client-perf-stats" request
        (let [body (transit-utils/parse-body request)]
          (client-perf-stats body))
        (rh/no-content))

  (POST "/client-perf-slow-frame" request
        (rh/no-content)))

kasuko16:04:25

In the /client-perf-stats route the :body of the request is empty as it’s already been read

kasuko16:04:29

In the above the body is empty if it uses either compojure or compojure-api

juhoteperi16:04:47

yes, it doesn't matter at all which one your are using

juhoteperi17:04:04

ring middlewares are ran before route matching happens

juhoteperi17:04:15

I'd recommend just using api at the top-most handler, which I guess is the app-routes. I don't see benefit of only using it for api endpoints

kasuko17:04:32

We don’t make our top-most handler. The system handler component does

juhoteperi17:04:53

That will just do (routes api-endpoint app-endpoint)

juhoteperi17:04:22

Which is same as (fn [req] (or (api-endpoint req) (app-endpoint req)))

kasuko17:04:20

alright, I will remove the api-endpoint and most likely just add it to the app-routes as per your advice

kasuko17:04:06

Thanks for the help!

jarrodctaylor23:04:03

I have a compojure-api app which contains an endpoint accepting file uploads. Basic functionality works as desired however, I'm running into a 413 Request Entity Too Large for files over 8MB. How can the max allowed size be specified?