首页 > 解决方案 > 如何使中间件仅在`:swagger {:deprecated true}`时放置响应标头?

问题描述

我们使用 compojure-api 在我们的环应用程序中获得一些不错的招摇集成。元数据的:swagger {:deprecated true}作用就像是让 swagger 页面正确的冠军,但我有一个要求,当路由是:swagger {:deprecated true}. 我正在努力弄清楚如何使用我一直用来进行类似响应标头操作的中间件模式来做到这一点。

(ns bob.routes
  (:require [clojure.tools.logging :as log]
            [compojure.api.sweet :refer :all]
            [ring.util.http-response :as status]
            [schema.core :as s]
            [ring.swagger.schema :as rs]))

(s/defschema BobResponse {:message (rs/describe String "Message")})

(defn wrap-bob-response-header [handler]
  (fn [request]
    (let [response (handler request)]
      ;; can I reach into the request or the response to see what
      ;; route served this and if it has the :swagger {:deprecated true}
      ;; meta on it and NOT emit the x-bob header if it does?
      (assoc-in response [:headers "x-bob"] "Robert"))))

(defroutes bob-routes
  (context "" []
    :middleware [wrap-bob-response-header]
    :tags ["bob"]
    :description ["Tease out how to do swagger driven response header"]
    (GET "/notdeprectated" [:as request]
      :swagger {:deprecated false}
      :new-relic-name "GET_notdeprecated"
      :return BobResponse
      (status/ok {:message "All is well"}))
    (GET "/isdeprecated" [:as request]
      :swagger {:deprecated true}
      :new-relic-name "GET_isdeprecated"
      :return BobResponse
      (status/ok {:message "You came to the wrong neighborhood."}))))

如何修改为仅在带有 的路线上wrap-bob-response-header发射?x-bob:swagger {:deprecated true}

标签: clojurecompojureringcompojure-api

解决方案


使用 Compojure-API,中间件在它们定义的路径上下文中就地调用。在您的示例中,wrap-bob-response-header还不知道请求将去向(或者它甚至会匹配任何内容)。如果它知道,您可以使用从请求中注入的路由信息​​(参见https://github.com/metosin/compojure-api/blob/master/src/compojure/api/api.clj#L71-L73)来确定如果端点设置了招摇信息。

您可以做的是将标头设置中间件仅安装到需要它的路由上。

有一个名为reitit的库(也由 Metosin 提供)通过应用路由优先架构解决了这个问题:首先完成全路径查找,然后应用中间件链。因此,所有中间件都知道它们挂载到的端点。中间件可以只查询端点数据(在请求时或在编译时)并采取相应的行动。他们甚至可以决定不登上那条特殊的路线。

Reitit 与 compojure-api 具有相同的功能,只是语法不同,例如完全数据驱动。

博客中的好例子:https ://www.metosin.fi/blog/reitit-ring/

PS。我是这两个库的合著者。

编辑。

匹配后向响应中注入数据的解决方案:

1)创建将数据(或元数据)添加到响应的中间件

2)添加或修改重组处理程序以将中间件从 1 挂载到端点,并使用给定的数据(在处理程序中可用)

3)读取响应管道中的数据并采取相应措施

(defn wrap-add-response-data [handler data]
  (let [with-data #(assoc % ::data data)]
    (fn
      ([request]
       (with-data (handler request)))
      ([request respond raise]
       (handler #(respond (with-data %)) raise)))))

(defmethod compojure.api.meta/restructure-param :swagger [_ swagger acc]
  (-> acc
      (assoc-in [:info :public :swagger] swagger)
      (update-in [:middleware] into `[[wrap-add-response-data ~swagger]])))

(def app
  (api
    (context "/api" []
      (GET "/:kikka" []
        :swagger {:deprecated? true}
        (ok "jeah")))))

(app {:request-method :get, :uri "/api/kukka"})
; {:status 200, :headers {}, :body "jeah", ::data {:deprecated? true}}

推荐阅读