W poprzedniej części naszego cyklu o Phoeniksie dowiedzieliśmy się jak funkcjonują modele i migracje na tej platformie oraz porównaliśmy ich działanie z działaniem modeli i migracji w Railsach. W dzisiejszym artykule chciałbym opisać cykl życia zapytania – od momentu, w którym jest ono wysyłane przez przeglądarkę do chwili, w której odpowiedź wraca do klienta. Cykl życia zapytania można ująć w dziewięciu krokach:
1. Zapytanie HTTP wysłane przez przeglądarkę.
Tutaj mamy do czynienia z dosyć prostą i standardową procedurą. Użytkownik wpisuje adres URL, np. https://moja-super-strona.pl/posts/zazolc-gesla-jazn. Przeglądarka wystosowuje odpowiednie zapytanie do serwera i przesyła je za pomocą protokołu HTTP/HTTPS.
2. Cowboy: serwer HTTP napisany w Erlangu
W chwili, gdy Cowboy otrzymuje zapytanie HTTP, tworzy strukturę reprezentującą połączenie, używając adaptera Cowboy Plug – struktura ta przyjmuje zazwyczaj nazwę conn. W kolejnych funkcjach będzie ona przekształcona w taki sposób, aby można było wygenerować odpowiedź na zapytanie. Cowboy używa jeszcze jednej biblioteki, ranch, do zarządzania pulą połączeń. Każde połączenie to osobny proces w wirtualnej maszynie Erlanga, co sprawia, że każde zapytanie jest całkowicie niezależne.
3. Plug
Plug to interfejs serwera w Elixirze. Jest on podobny do abstrakcji, takich jak np. rack, w Rubym. Plug daje nam do dyspozycji kilka gotowych implementacji: ochronę CSRF, sesję, logowanie, czy też serwowanie plików statycznych. W wielu aplikacjach webowych napisalibyśmy plug, który sprawdzałby czy użytkownik jest uwierzytelniony, a następnie, w zależności od odpowiedzi, udostępniłby zasób użytkownikowi lub też odesłał go do strony logowania.
4. Phoenix Endpoint
Phoenix Endpoint opisuje to, z jakich wtyczek składa się dana aplikacja. Prowadzi on do aplikacji Phoenix OTP. Phoenix wcale nie musi być głównym elementem danej aplikacji – może pozostawać jedynie jej częścią. Spójrzmy na wtyczki, które są definiowane w momencie stworzenia nowej aplikacji:
Pierwsza wtyczka służy do dostarczania plików statycznych – dodaje nagłówek cache HTTP po to, by klient wiedział, że nie musi danych plików ściągać ponownie. Kolejne dwie wtyczki umożliwiają hot reload. Następnych dwóch wtyczek używamy do dodawania identyfikatora (id) do zapytania (wyszukiwanie zapytań w logach tworzonych przez inne platformy, np. Elixir, może być bardzo trudne) oraz do logowania odbywających się procesów poprzez implementację loggera, która jest zdefiniowana w pliku konfiguracji projektu. Plug.Parsers używamy z kolei do przetwarzania zawartości zapytania – to właśnie ta wtyczka wyciąga parametry z zapytania. Plug.MethodOverride daje nam możliwość nadpisania metody HTTP, zaś Plug.Head zmienia metodę HEAD HTTP na GET. Ostatnie dwie wtyczki umożliwiają zapisywanie sesji i routera wykorzystywanych przez aplikację.
5. Phoenix Router
Phoeniksowy Router służy do łączenia ścieżki zapytania klienta z określonym kontrolerem i operacją, która ma zostać wywołana. Dodatkowo, w routerze definiujemy wtyczki i pipeline'y (zestawy wtyczek), przez które ma przepływać nasze zapytanie. Rzućmy okiem na domyślny router:
https://gist.github.com/azranel/4adb283bf83945ec4b1b696bcc117ff5
Możemy tu zobaczyć dwa pipeline'y: pierwszy stosuje się do przeglądarki, zaś drugi obsługuje wywołania API. Moglibyśmy dodać również kolejny pipeline, np. :authenticated, w którym sprawdza się czy użytkownik jest zalogowany oraz pobiera dane użytkownika do późniejszego użycia w kontrolerach i widokach.
6. Phoenix Controller
Controller obsługuje konkretne operacje: pobiera dane z bazy danych, wywołuje usługi wykonujące logikę biznesową, renderuje templatki i pliki JSON.
7. Phoenix View
W Phoenix View umieszczamy funkcje pomocnicze używane przez templatki. Można to interpretować w kategoriach szablonów Presentera.
8. Phoenix Template
Ta funkcja generuje kod HTML, który będzie dodany do treści zapytania. Jest odpowiednikiem view z Ruby on Rails.
9. HTTP Response
W chwili, gdy widok renderuje templatkę, wywołuje on funkcję send_resp, która następnie zwraca odpowiedź HTTP do klienta. Tutaj znajdziecie kod źródłowy funkcji renderowania templatki. send_resp jest dostępny tutaj.
W tym momencie użytkownik może już zobaczyć naszą wspaniałą aplikację! Moim zdaniem, cykl życia zapytania w Phoeniksie jest dużo mniej złożony niż ten w Railsach.