{"id":97945,"date":"2025-02-18T00:39:55","date_gmt":"2025-02-17T21:09:55","guid":{"rendered":"https:\/\/nabfollower.com\/blog\/clojure-%d8%b9%d8%a7%d9%84%db%8c-%d8%a7%d8%b3%d8%aa-part-12\/"},"modified":"2025-02-18T00:39:55","modified_gmt":"2025-02-17T21:09:55","slug":"clojure-%d8%b9%d8%a7%d9%84%db%8c-%d8%a7%d8%b3%d8%aa-part-12","status":"publish","type":"post","link":"https:\/\/nabfollower.com\/blog\/clojure-%d8%b9%d8%a7%d9%84%db%8c-%d8%a7%d8%b3%d8%aa-part-12\/","title":{"rendered":"Clojure \u0639\u0627\u0644\u06cc \u0627\u0633\u062a !!! [PART 12]"},"content":{"rendered":"<div data-article-id=\"2284517\" id=\"article-body\">\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight clojure\"><code><span class=\"p\">(<\/span><span class=\"nf\">ns<\/span><span class=\"w\"> <\/span><span class=\"n\">chain-of-responsibility<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"no\">:require<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">clojure.pprint<\/span><span class=\"w\"> <\/span><span class=\"no\">:as<\/span><span class=\"w\"> <\/span><span class=\"n\">pp<\/span><span class=\"p\">]))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Request Processing Chain ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">defprotocol<\/span><span class=\"w\"> <\/span><span class=\"n\">RequestHandler<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">])<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">]))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Authentication Handler ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">defrecord<\/span><span class=\"w\"> <\/span><span class=\"n\">AuthenticationHandler<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">next-handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"n\">RequestHandler<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">if-let<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">auth-token<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:auth-token<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)]<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">auth-token<\/span><span class=\"w\"> <\/span><span class=\"s\">\"valid-token\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\">\n          <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\"> \n                         <\/span><span class=\"p\">(<\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:authenticated<\/span><span class=\"w\"> <\/span><span class=\"n\">true<\/span><span class=\"p\">))<\/span><span class=\"w\">\n          <\/span><span class=\"p\">(<\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:authenticated<\/span><span class=\"w\"> <\/span><span class=\"n\">true<\/span><span class=\"p\">))<\/span><span class=\"w\">\n        <\/span><span class=\"p\">{<\/span><span class=\"no\">:error<\/span><span class=\"w\"> <\/span><span class=\"s\">\"Invalid authentication token\"<\/span><span class=\"p\">})<\/span><span class=\"w\">\n      <\/span><span class=\"p\">{<\/span><span class=\"no\">:error<\/span><span class=\"w\"> <\/span><span class=\"s\">\"Missing authentication token\"<\/span><span class=\"p\">}))<\/span><span class=\"w\">\n\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">_<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;AuthenticationHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Authorization Handler ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">defrecord<\/span><span class=\"w\"> <\/span><span class=\"n\">AuthorizationHandler<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">next-handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"n\">RequestHandler<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:authenticated<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">contains?<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"no\">:admin<\/span><span class=\"p\">)<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\">\n          <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\"> \n                         <\/span><span class=\"p\">(<\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:authorized<\/span><span class=\"w\"> <\/span><span class=\"n\">true<\/span><span class=\"p\">))<\/span><span class=\"w\">\n          <\/span><span class=\"p\">(<\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:authorized<\/span><span class=\"w\"> <\/span><span class=\"n\">true<\/span><span class=\"p\">))<\/span><span class=\"w\">\n        <\/span><span class=\"p\">{<\/span><span class=\"no\">:error<\/span><span class=\"w\"> <\/span><span class=\"s\">\"Insufficient permissions\"<\/span><span class=\"p\">})<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\">\n        <\/span><span class=\"n\">request<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">_<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;AuthorizationHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Validation Handler ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">defrecord<\/span><span class=\"w\"> <\/span><span class=\"n\">ValidationHandler<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">next-handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"n\">RequestHandler<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">and<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\">\n             <\/span><span class=\"p\">(<\/span><span class=\"nb\">map?<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">))<\/span><span class=\"w\">\n             <\/span><span class=\"p\">(<\/span><span class=\"nb\">every?<\/span><span class=\"w\"> <\/span><span class=\"nb\">string?<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">vals<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">))))<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\"> \n                       <\/span><span class=\"p\">(<\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:validated<\/span><span class=\"w\"> <\/span><span class=\"n\">true<\/span><span class=\"p\">))<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:validated<\/span><span class=\"w\"> <\/span><span class=\"n\">true<\/span><span class=\"p\">))<\/span><span class=\"w\">\n      <\/span><span class=\"p\">{<\/span><span class=\"no\">:error<\/span><span class=\"w\"> <\/span><span class=\"s\">\"Invalid request data format\"<\/span><span class=\"p\">}))<\/span><span class=\"w\">\n\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">_<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;ValidationHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Logging Handler ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">defrecord<\/span><span class=\"w\"> <\/span><span class=\"n\">LoggingHandler<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">next-handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"n\">RequestHandler<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\nProcessing request:\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">pp\/pprint<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">dissoc<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"w\"> <\/span><span class=\"no\">:handler<\/span><span class=\"p\">))<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"k\">let<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">response<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\">\n                    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\">\n                    <\/span><span class=\"n\">request<\/span><span class=\"p\">)]<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\nResponse:\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nf\">pp\/pprint<\/span><span class=\"w\"> <\/span><span class=\"n\">response<\/span><span class=\"p\">)<\/span><span class=\"w\">\n      <\/span><span class=\"n\">response<\/span><span class=\"p\">))<\/span><span class=\"w\">\n\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">_<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;LoggingHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Cache Handler ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"k\">def<\/span><span class=\"w\"> <\/span><span class=\"n\">request-cache<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">atom<\/span><span class=\"w\"> <\/span><span class=\"p\">{}))<\/span><span class=\"w\">\n\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">defrecord<\/span><span class=\"w\"> <\/span><span class=\"n\">CacheHandler<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">next-handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n  <\/span><span class=\"n\">RequestHandler<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">this<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">if-let<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">cached<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"o\">@<\/span><span class=\"n\">request-cache<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">))]<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nf\">do<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"Cache hit for request:\"<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">))<\/span><span class=\"w\">\n        <\/span><span class=\"n\">cached<\/span><span class=\"p\">)<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"k\">let<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">response<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\">\n                      <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">next-handler<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\">\n                      <\/span><span class=\"n\">request<\/span><span class=\"p\">)]<\/span><span class=\"w\">\n        <\/span><span class=\"p\">(<\/span><span class=\"nb\">when<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\">\n          <\/span><span class=\"p\">(<\/span><span class=\"nf\">swap!<\/span><span class=\"w\"> <\/span><span class=\"n\">request-cache<\/span><span class=\"w\"> <\/span><span class=\"nb\">assoc<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"n\">request<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"n\">response<\/span><span class=\"p\">))<\/span><span class=\"w\">\n        <\/span><span class=\"n\">response<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n  <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">_<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;CacheHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">handler<\/span><span class=\"p\">)))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Request Processing ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"k\">defn<\/span><span class=\"w\"> <\/span><span class=\"n\">build-chain<\/span><span class=\"w\"> <\/span><span class=\"p\">[]<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"nb\">-&gt;<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;LoggingHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">nil<\/span><span class=\"p\">)<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;CacheHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">nil<\/span><span class=\"p\">))<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;AuthenticationHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">nil<\/span><span class=\"p\">))<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;AuthorizationHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">nil<\/span><span class=\"p\">))<\/span><span class=\"w\">\n      <\/span><span class=\"p\">(<\/span><span class=\"nf\">set-next<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">-&gt;ValidationHandler<\/span><span class=\"w\"> <\/span><span class=\"n\">nil<\/span><span class=\"p\">))))<\/span><span class=\"w\">\n\n<\/span><span class=\"c1\">;; === Example Usage ===<\/span><span class=\"w\">\n<\/span><span class=\"p\">(<\/span><span class=\"k\">defn<\/span><span class=\"w\"> <\/span><span class=\"n\">run-examples<\/span><span class=\"w\"> <\/span><span class=\"p\">[]<\/span><span class=\"w\">\n  <\/span><span class=\"p\">(<\/span><span class=\"k\">let<\/span><span class=\"w\"> <\/span><span class=\"p\">[<\/span><span class=\"n\">chain<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">build-chain<\/span><span class=\"p\">)]<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\n=== Valid Admin Request ===\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">chain<\/span><span class=\"w\">\n                   <\/span><span class=\"p\">{<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"s\">\"req-1\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:auth-token<\/span><span class=\"w\"> <\/span><span class=\"s\">\"valid-token\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"o\">#<\/span><span class=\"p\">{<\/span><span class=\"no\">:admin<\/span><span class=\"p\">}<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"s\">\"name\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"John\"<\/span><span class=\"w\">\n                          <\/span><span class=\"s\">\"action\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"read\"<\/span><span class=\"p\">}})<\/span><span class=\"w\">\n\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\n=== Invalid Token ===\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">chain<\/span><span class=\"w\">\n                   <\/span><span class=\"p\">{<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"s\">\"req-2\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:auth-token<\/span><span class=\"w\"> <\/span><span class=\"s\">\"invalid-token\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"o\">#<\/span><span class=\"p\">{<\/span><span class=\"no\">:admin<\/span><span class=\"p\">}<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"s\">\"name\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"John\"<\/span><span class=\"p\">}})<\/span><span class=\"w\">\n\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\n=== Missing Token ===\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">chain<\/span><span class=\"w\">\n                   <\/span><span class=\"p\">{<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"s\">\"req-3\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"o\">#<\/span><span class=\"p\">{<\/span><span class=\"no\">:admin<\/span><span class=\"p\">}<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"s\">\"name\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"John\"<\/span><span class=\"p\">}})<\/span><span class=\"w\">\n\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\n=== Insufficient Permissions ===\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">chain<\/span><span class=\"w\">\n                   <\/span><span class=\"p\">{<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"s\">\"req-4\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:auth-token<\/span><span class=\"w\"> <\/span><span class=\"s\">\"valid-token\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"o\">#<\/span><span class=\"p\">{<\/span><span class=\"no\">:user<\/span><span class=\"p\">}<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"s\">\"name\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"John\"<\/span><span class=\"p\">}})<\/span><span class=\"w\">\n\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\n=== Invalid Data ===\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">chain<\/span><span class=\"w\">\n                   <\/span><span class=\"p\">{<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"s\">\"req-5\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:auth-token<\/span><span class=\"w\"> <\/span><span class=\"s\">\"valid-token\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"o\">#<\/span><span class=\"p\">{<\/span><span class=\"no\">:admin<\/span><span class=\"p\">}<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"s\">\"name\"<\/span><span class=\"w\"> <\/span><span class=\"mi\">123<\/span><span class=\"p\">}})<\/span><span class=\"w\">\n\n    <\/span><span class=\"p\">(<\/span><span class=\"nb\">println<\/span><span class=\"w\"> <\/span><span class=\"s\">\"\\n=== Cached Request ===\"<\/span><span class=\"p\">)<\/span><span class=\"w\">\n    <\/span><span class=\"p\">(<\/span><span class=\"nf\">handle-request<\/span><span class=\"w\"> <\/span><span class=\"n\">chain<\/span><span class=\"w\">\n                   <\/span><span class=\"p\">{<\/span><span class=\"no\">:id<\/span><span class=\"w\"> <\/span><span class=\"s\">\"req-1\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:auth-token<\/span><span class=\"w\"> <\/span><span class=\"s\">\"valid-token\"<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:roles<\/span><span class=\"w\"> <\/span><span class=\"o\">#<\/span><span class=\"p\">{<\/span><span class=\"no\">:admin<\/span><span class=\"p\">}<\/span><span class=\"w\">\n                    <\/span><span class=\"no\">:data<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"s\">\"name\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"John\"<\/span><span class=\"w\">\n                          <\/span><span class=\"s\">\"action\"<\/span><span class=\"w\"> <\/span><span class=\"s\">\"read\"<\/span><span class=\"p\">}})))<\/span><span class=\"w\">\n\n\n<\/span><span class=\"p\">(<\/span><span class=\"nf\">run-examples<\/span><span class=\"p\">)<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0631\u0627 \u0648\u0627\u0631\u062f \u06a9\u0646\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>(ns chain-of-responsibility (:require [clojure.pprint :as pp])) ;; === Request Processing Chain === (defprotocol RequestHandler (handle-request [this request]) (set-next [this handler])) ;; === Authentication Handler === (defrecord AuthenticationHandler [next-handler] RequestHandler (handle-request [this request] (if-let [auth-token (:auth-token request)] (if (= auth-token &#8220;valid-token&#8221;) (if next-handler (handle-request next-handler (assoc request :authenticated true)) (assoc request :authenticated true)) {:error &#8220;Invalid authentication &hellip;<\/p>\n","protected":false},"author":2,"featured_media":97946,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/media2.dev.to\/dynamic\/image\/width=1000,height=500,fit=cover,gravity=auto,format=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0wrb9laph9xgxxq9f74.jpg","fifu_image_alt":"","footnotes":""},"categories":[339],"tags":[],"class_list":["post-97945","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/97945","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/comments?post=97945"}],"version-history":[{"count":0,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/97945\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media\/97946"}],"wp:attachment":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media?parent=97945"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/categories?post=97945"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/tags?post=97945"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}