Clojure web development: Ring Middleware
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.
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 posdtatě 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):
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 (->
):
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 bysme psali RESTovou službu, která přijímá data pomocí PUT. Pomineme funkční logiku, zpracování dat i routování a budeme se soustředit 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.
Teď už stačí jen dát tyto dva middlewary dohromady, abychom dostali požadované chování:
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.
Související články
- Clojure web development: Ring
- Clojure web development: Compojure (TBD)
- Clojure web development: Hiccup (TBD)