2015-01-19 7 views
13

나는 링 + compojure 응용 프로그램을 가지고 있으며 경로가 웹 응용 프로그램의 일부인지 아니면 api의 일부인지에 따라 다른 미들웨어를 적용하려고합니다 (이는 json 기반).Ring 및 Compojure를 사용하여 서로 다른 미들웨어로 앱 및 API 경로 제공

스택 오버플로 및 기타 포럼에서이 질문에 대한 답변을 찾았지만 이러한 대답은 제가 사용 해본 솔루션보다 복잡해 보입니다. 나는 내가 그것을하고있는 방법과 나의 해결책에서 누락되었을 수있는 것에 결점이 있는지 알고 싶었다. 내가하는 일의 매우 단순화 된 버전은

(defroutes app-routes 
    (GET "/" [req] dump-req) 
    (route/not-found "Not Found")) 

(defroutes api-routes 
    (GET "/api" [req] dump-req)) 

(def app 
    (routes (-> api-routes 
       (wrap-defaults api-defaults)) 
      (-> app-routes 
       (wrap-defaults site-defaults)))) 

여기에 나와있는 것보다 더 많은 미들웨어가 있음에 유의하십시오.

내가 만난 유일한 제한점은 app-routes에 발견되지 않은 경로가 있기 때문에 마지막으로 올 필요가 있거나 API 경로를 찾기 전에 트리거된다는 것입니다.

이것은 내가 찾은 다른 솔루션보다 간단하고 유연합니다. ring.middleware.conditional과 같은 추가 조건부 미들웨어를 사용하거나 더 복잡한 라우팅 정의가있는 곳이있는 것처럼 보입니다. 추가 defroutes 레이어 및 "*"등 defroutes을 정의해야 할 필요

내가 여기에 뭔가 미묘한 것 같아요 그리고 내 접근 방식이 작동하는 동안 그것은 예기치 않은 동작이나 일부 상황에서 결과가 발생할 것입니다

+0

여기에'routes' 란 무엇입니까? -got it : http : //weavejester.github. io/compojure/compojure.core.html # var-routes –

답변

16

당신이 맞다면, 주문에 문제가있어서 누락 된 미묘한 부분이 있습니다 - api-routes에 적용되는 미들웨어는 exec입니다. 모든 요청에 ​​대해 uted.

(defn wrap-app-middleware 
    [handler] 
    (fn [req] 
    (println "App Middleware") 
    (handler req))) 

(defn wrap-api-middleware 
    [handler] 
    (fn [req] 
    (println "API Middleware") 
    (handler req))) 

(defroutes app-routes 
    (GET "/" _ "App") 
    (route/not-found "Not Found")) 

(defroutes api-routes 
    (GET "/api" _ "API")) 

(def app 
    (routes (-> api-routes 
       (wrap-api-middleware)) 
      (-> app-routes 
       (wrap-app-middleware)))) 

및 REPL 세션 : - wrap-routes

> (require '[ring.mock.request :as mock]) 
> (app (mock/request :get "/api")) 
API Middleware 
... 
> (app (mock/request :get "/")) 
API Middleware 
App Middleware 
... 

Compojure들이 일치 된 후 루트 에 미들웨어를 적용 좋은 기능 및 도우미를 가지고

이 코드를 고려

(def app 
    (routes (-> api-routes 
       (wrap-routes wrap-api-middleware)) 
      (-> app-routes 
       (wrap-routes wrap-app-middleware)) 
      (route/not-found "Not Found"))) 

> (app (mock/request :get "/api")) 
API Middleware 
... 
> (app (mock/request :get "/")) 
App Middleware 
... 
+0

감사합니다. 머리에 대한 내 관심사에 부딪혔고 더 중요한 것은 랩 경로 포인터로 올바른 방향으로 안내해주었습니다. –

+1

이 방법으로 경고에 플래그를 지정하기 만하면됩니다. site-defaults 구성을 사용하는 링 wrap-defaults 미들웨어에서 올바르게 작동하지 않습니다. 문제는 route/not-found 처리기가 손상된다는 것입니다. wrap-defaults로 응답 헤더를 무응답으로 삽입함으로써 처리기가 요청을 처리 한 것처럼 보입니다. 반환 코드는 200이고 내용은 없습니다. ring-defaults로 문제를 기록했습니다. –

+1

옵션이 있다면 두 개의 링 앱을 만들어 다른 웹 컨텍스트에 마운트 할 수 있습니다. immutant를 사용하면 두 개의 핸들러를 간단하게 만들 수 있고 두 가지 다른 미들웨어를 사용하여 서로 다른 경로에 마운트 할 수 있습니다. '(web/run app)'및'(web/run api : path "/ api)' – egli

0

sim pler 솔루션은 ... (응용 프로그램에서이 코드를 사용하여 예제에 코드를 적용했습니다.)

(defn make-api-handler 
    [] 
    (-> api-routes 
     (wrap-defaults api-defaults))) 

(defn make-app-handler 
    [] 
    (-> app-routes 
     (wrap-defaults site-defaults))) 

(def app 
    (let [api-handler-fn (make-api-handler) 
     app-handler-fn (make-app-handler)] 
    (fn [request] 
     (if (clojure.string/starts-with? (:uri request) "/api") 
     (api-handler-fn request) 
     (app-handler-fn request)))))