Přejít k navigační liště

Zdroják » Různé » Ring Middleware

Ring Middleware

Články ‐ ‐ Různé ‐

V minulém článku jsme se podívali na úplně nejzákladnější základy webového vývoje v Clojure – jak zpracovat HTTP request a response pomocí knihovny Ring. Tu nejzajímavější část Ringu – Middleware – jsme ale zmínili jen letmo a byla by škoda se do tohoto zajímavého konceptu trochu více neponořit.

Nálepky:

Text vyšel původně na autorově blogu.

Připomenutí základních konceptů

Než zrychlíme z 0 na 100, připomenu čtyři základní komponenty Ringu:

  • Handler – funkce, která přijímá mapu reprezentující HTTP request a vrací mapu představující HTTP response.
  • Request – mapa reprezentující HTTP request, která obsahuje sadu „standardních“ klíčů, které nám budou povědomé ze Servletu: :server-port, :server-name, :remote-address, :request-method ad.
  • Response – mapa, představující HTTP response, která obsahuje tři klíče: :status, :header, :body.
  • Middleware – funkce, která handleru přidá dodatečné funkcionality. Věci jako session, cookies či parametry jsou řešené middlewarem.

Anatomie Middlewaru

Middleware je funkce vyššího řádu, která přijímá jako parameter handler a vrací jiný handler (jako anonymní funkci), který nějakým způsobem obohatil buď request, nebo response. V podstatě se dá na middleware nahlížet jako na takový funkcionální decorator.

Pokud se podíváme na obecnou podobu middlewaru, má často následující strukturu (kudos to StackOverflow):

(defn wrap-blank-middleware
  "Blank middleware demonstrating common structure."
  [handler]
  (fn [request]
    ; Do some magic with the request
    (let [response (handler request)]
      ; Do some magic with the response
      ; and return the response.
      response)))

Balení middlewaru

Middleware většinou bývá jenom velmi jednoduchá funkce, takže komplexnější chování dostaneme zřetězením jednotlivých middlewarů, a to tak, že je postupně zabalujeme do sebe:

Způsob, jak middlewary do sebe zabalit, je dvojí – buď klasické zanořené funkce, nebo častější způsob je pomocí thread-first makra (->):

; "Classical" middleware wrapping
(middleware-3 (middleware-2 (middleware-1 handler)))

; Middleware wrapping via threading macro
(-> handler (middleware-1) (middleware-2) (middleware-3))

A jen pro úplnost – zabalit se anglicky řekne „wrap“, proto se používá konvence, že middlewary začínají prefixem wrap-.

Ilustrační příklad

Řekněme, že bychom psali RESTovou službu, která přijímá data pomocí PUT. Pomineme funkční logiku, zpracování dat i routování a soustředíme se jen na middleware, který se bude chovat následovně:

  • Pokud request metoda není PUT, vrátí middleware status 405 a text „Method Not Allowed“.
  • Pokud je request metoda PUT, vrátí status 204 (No Content) a prázdné body.

Aby middlewary byly malé a znovupoužitelné, rozdělíme si každou funkčnost, popsanou v předešlých odrážkách, do samostatné funkce:

  • wrap-no-content bude vracet status 204 a prázdné body.
  • wrap-put-allowed vrátí buď 405 (a popis v body), pokud metoda není PUT, nebo jenom zavolá původní handler.
(defn wrap-no-content
  "Middleware that returns a 204 No Content
  from the wrapped handler."
  [handler]
  (fn [request]
    (let [response (handler request)]
      (-> response
          (assoc :status 204)
          (dissoc :body)))))

(defn wrap-put-allowed
  "Middleware that returns a 405 Method Not Allowed
  if the request doesn't have :put method."
  [handler]
  (fn [request]
    (if (= (:request-method request) :put)
      (handler request)
      (let [response (handler request)]
        (-> response
            (assoc :status 405)
            (assoc :body "Method Not Allowed"))))))

 

Teď už stačí jen dát tyto dva middlewary dohromady, abychom dostali požadované chování:

(defn wrap-put-no-content
  "Middleware that returns a 204 No Content
  if the request method is PUT, otherwise
  a 405 Method Not Allowed."
  [handler]
  (-> handler
      (wrap-no-content)
      (wrap-put-allowed)))

GitHub projekt

Pokud vám výše popsané principy neštymují dohromady, mrkněte na GitHub, kde je malý spustitelný projektík, plus pár middleware unit testů:

Co příště?

O Ringu a jeho middlewarech by se dalo psát ještě dlouho, ale je čas pokročit. Logicky následným tématem je Compojure – routovací knihovna pro Ring webové aplikace.

Komentáře

Odebírat
Upozornit na
guest
0 Komentářů
Nejstarší
Nejnovější Nejvíce hlasů

WebSocket: Jak dostat webovou aplikaci do reálného času

Chat, živé notifikace, společná úprava dokumentu nebo průběžně aktualizované kurzy. Uživatelé dnes čekají, že se webová aplikace změní ve chvíli, kdy se změní data, a ne až po stisknutí klávesy F5. Protokol WebSocket je nejrozšířenější způsob, jak mezi prohlížečem a serverem vytvořit trvalý obousměrný kanál. V článku se podíváme, jak funguje pod kapotou, jak ho použít v prohlížeči i na serveru a na co si dát pozor při nasazení do produkce.

Zahoďte knihovny: dropdowny, tooltipy a přechody stránek jen s HTML a CSS

Rozbalovací menu, tooltip, modální okno a plynulý přechod mezi stránkami. Ještě nedávno čtyři důvody, proč do projektu přidat několik knihoven a desítky kilobajtů JavaScriptu. V roce 2026 už to všechno zvládne prohlížeč sám. Ukážeme si, jak na to s Popover API, CSS anchor positioningem a View Transitions, a také kde mají své limity.

Rok po Shai-Hulud: co se změnilo na npm a co musíte udělat do ledna

Před rokem začal registrem npm procházet samošířící červ Shai-Hulud. Od té doby se útoky na dodavatelský řetězec JavaScriptu staly pravidelnou záležitostí a npm postupně přepisuje pravidla publikování. Projdeme, co se za ten rok stalo, jak dnes bezpečně publikovat balíček, co musíte stihnout do ledna 2027 a jak se bránit jako uživatel balíčků.