Najważniejsze zagadnienia, które musisz znać
5 godz. 53 min · JavaScript · Full-stack i Programowanie
Adam GospodarczykPrzesyłanie oraz transformacja danych to jeden z najważniejszych elementów działania każdej aplikacji. Dobre zrozumienie tego w jaki sposób odbywa się ten proces, daje równocześnie lepsze zrozumienie całej struktury oraz podejmowania decyzji projektowych. W tym kursie znajdziesz lekcje, które pozwolą Ci uporządkować wiedzę na temat protokołu HTTP oraz formatów wymiany danych.
REST oraz GraphQL to nadal nieodłączone zagadnienia tematu wymiany informacji w kontekście aplikacji webowych. Pomimo tego, że ich koncepcje zwykle są bardzo dobrze opisane w różnych źródłach, tak ich wykorzystanie "na produkcji" potrafi sprawić problemy. W szczególności gdy weźmiemy pod uwagę, wyjątki oraz fakt, że nie każda aplikacja będzie wymagać implementacji REST czy GraphQL w 100%. W tym kursie znajdziesz wiele praktycznych wskazówek związanych z pracą z REST API oraz wprowadzenie do pracy z GraphQL.
Niektóre błędy w aplikacji są bardzo pożądane, w szczególności gdy jasno informują użytkownika o tym, co się wydarzyło oraz o tym, co może z tym zrobić. Pomimo tego, że w wielu przypadkach opracowanie komunikatów leży w rękach osoby odpowiedzialnej za copywriting (i/lub ux writing), tak sama implementacja tych komunikatów odbywa się po stronie kodu. Nie rzadko okazuje się, że poprawna i skuteczna walidacja danych oraz obsługa błędów nie jest oczywista w "produkcyjnych" sytuacjach. W tym kursie znajdziesz najczęściej spotykane problemy oraz sposoby ich rozwiązania.
Bazy danych są praktycznie nieodłączną częścią każdej aplikacji. W roli full-stacka prędzej czy później przyjdzie Ci z nimi pracować a nie rzadko nawet projektować oraz rozbudowywać ich struktury. W tym kursie znajdziesz informacje o bazach danych, które pozwolą Ci je zrozumieć oraz od razu poznać użyteczne techniki, które pomogą Ci w pracy z nimi, zarówno na produkcji jak i w środowisku lokalnym czy testowym.
Nie wszystkie informacje w aplikacji są publiczne. Niektóre wprost nie mogą takie być. Z tego powodu niezbędne są sposoby na to aby poznać a potem weryfikować tożsamość użytkownika, by na jej podstawie przydzielać mu dostęp wyłącznie do zasobów, do których odczytywania posiada uprawnienia. Istnieje wiele technik, które umożliwiają zarządzanie dostępem do danych i w tym kursie poznasz najważniejsze z nich. Dowiesz się nie tylko w jaki sposób zabezpieczać dane ale poznasz też najpopularniejsze sposoby na to aby te zabezpieczenia łamać i obchodzić. Mając świadomość takiej możliwości, będziesz w stanie lepiej podejmować decyzje o tym jak projektować dostęp do informacji.
Istnieją problemy charakterystyczne dla niemal każdej aplikacji. W związku z ich powszechnością, istnieje też szereg rozwiązań lub sposobów na to, aby możliwie zredukować ich następstwa. Na przestrzeni lekcji tego kursu zobaczysz wiele przykładów, które pomogą Ci w codziennej pracy a niekiedy nawet, pozwolą uniknąć błędów, których konsekwencje nie zawsze występują natychmiast.
Kurs powstał z myślą o osobach, które chcą rozwijać się w roli full-stack web developera / developerki, przeprowadzając przez najważniejsze zagadnienia z obszaru wymiany, transformacji oraz przechowywania informacji w aplikacji oraz pomiędzy aplikacjami. Jeżeli potrzebujesz zobaczyć szeroką perspektywę tego, w jaki sposób dane przepływają pomiędzy różnymi częściami aplikacji, lub ugruntować swoją wiedzę na ten temat, to ten kurs jest miejscem, którego szukasz.
Myślę, że warto teraz porozmawiać o
drugiej części, czyli jak działa obsługa zapytania po stronie backendu.
Tutaj poniekąd już wiemy, że obsługujemy
zapytania, które trafiają na określony endpoint i na podstawie tego endpoint np.
ng links czyli web server decyduje o tym w
jaki sposób obsłużyć to zapytanie lub też bardziej w które miejsce je przekazać i
czy ewentualnie trzeba je w jakiś sposób modyfikować.
W naszym przypadku zapytanie trafia bezpośrednio do aplikacji np.
na jest.
Następnie już wewnątrz tej aplikacji funkcjonuje tzw.
router i on również odpowiedzialny jest za to, aby zdecydować, w które miejsce naszej
aplikacji ma trafić to zapytanie, aby zostało obsłużone.
W momencie, gdy ja na tym etapie mówię o
miejscu, mam na myśli tak zwaną akcję kontrolera.
Akcja kontrolera to nic innego jak po
prostu funkcja przypisana do konkretnego endpoint oraz konkretnej metody.
Co więcej, zanim informacja trafi
bezpośrednio do takiej funkcji kontrolera, może przejść przez tzw.
middleware, czyli funkcje, które występują pomiędzy routerem a kontrolerem.
Przykładem takiej funkcji może być
middleware odpowiedzialny za uwierzytelnienie połączenia, czyli
przykładowo odczytanie nagłówka Auto Dizajn i sprawdzenie, czy przekazany tam
token jest poprawny oraz z jakim użytkownikiem jest powiązany.
Na tym etapie middleware może też
zmodyfikować obiekt żądania chociażby w taki sposób, że dołączy do
niego informacje na temat bieżącego użytkownika, tak abyśmy nie musieli
powtarzać tej akcji w każdej z akcji kontrolera.
Następnie mamy sam kontroler, który w
zależności od tego, w jaki sposób ułożona jest dalsza część naszej aplikacji, może
skontaktować się z repozytorium bądź serwisem, bądź też jednym i drugim,
ponieważ to właśnie te dwie warstwy mogą odpowiadać za bezpośredni kontakt z bazą
danych bądź też innymi zewnętrznymi usługami.
W każdym razie w przypadku naprawdę małych aplikacji może dojść do sytuacji, w której
to kontroler będzie kontaktował się z bazą danych.
Aczkolwiek jest to powszechnie uznawane
jako zła praktyka i warto posiadać przynajmniej tą warstwę serwisową.
Jeżeli chodzi o architekturę aplikacji w tym kontekście, to w praktyce będziemy
jeszcze omawiać na przykładzie Nest, gdzie jest.
Następnie po kontrolerze tak jak
wspomniałem mamy bazę danych i tutaj, podczas gdy ona sama odpowiedzialna jest
wyłącznie za przechowywanie danych, tak jednocześnie mamy tutaj do czynienia np.
ze SQL, czyli językiem odpowiedzialnym za komunikowanie się z tą bazą danych.
W większości przypadków w momencie, gdy pracujemy np.
z innymi backend nowymi technologiami, w celu tej komunikacji wykorzystujemy
narzędzia takie jak ORM bądź Query Builder.
Na koniec dnia jednak operacje, które wykonujemy na bazie danych sprowadzają się
do odczytywania bądź zapisywania, w tym też usuwania danych.
I zasadniczo te wszystkie warstwy prowadzą
do tego, aby przygotować odpowiedź, która trafi z powrotem do klienta.
Aczkolwiek tak jak wspomniałem, to na nas spoczywa odpowiedzialność związana z
ustawieniem odpowiedniego statusu oraz tutaj odpowiedzi.
Naturalnie to wszystko co tutaj omawiamy
to pewien uproszczony schemat, który pozwala Ci z lotu ptaka zrozumieć, co
mniej więcej dzieje się po stronie backendu.
Aczkolwiek trzeba zaznaczyć, że ten przepływ informacji po stronie backendu
może być zdecydowanie bardziej złożony i uwzględniać wiele dodatkowych kroków.
Jednocześnie też czasem może zdarzyć się,
że niektóre z tych warstw nie będą potrzebne, bo np.
nie będzie konieczności kontaktowania się
z bazą danych czy wykonywania jakichkolwiek customowe.
Do tego, aby modyfikować obiekt żądania
bądź jakkolwiek kontrolować dostęp do zasobów.
Myślę, że na tym etapie najważniejsze jest dla Ciebie to, aby stało się jasne, że w
pierwszej kolejności zapytania przekazywane są do odpowiedniej aplikacji,
następnie do odpowiedniego miejsca w tej aplikacji.
Potem są ewentualnie weryfikowane pod różnymi względami bądź też modyfikowane i
dopiero wtedy są obsługiwane z pomocą kontrolerów, które mogą ewentualnie łączyć
się z bazą danych po to, aby odczytywać oraz zapisywać dane.
No i ostatecznie również kontrolery dbają o to, aby przygotować strukturę odpowiedzi
i odrzucić ją do użytkownika na koniec dnia.
Jednak to wszystko leży w Twojej
odpowiedzialności, aby zadbać o cały ten przepływ informacji.
Zapraszamy więc teraz jak to wszystko może
wyglądać na przykładzie bardzo prostej aplikacji Messages.
Mianowicie sama aplikacja ma tutaj swój
plik główny, w którym jest tworzone i następnie też odpowiednio.
Akurat w tym przypadku za pomocą modułu
jest łączona zarówno z kontrolerem oraz serwisem.
I to właśnie o tym kontrolerze mówiłem,
gdzie akurat w tym przypadku odpowiada on na endpoint API, a wewnątrz niego znajdują
się akcje, z czego pierwsza odpowiada na dodatkowy segment users.
Oznacza to, że jeżeli wykonamy zapytanie
na wpis też i users zostanie wykonana ta akcja.
Czyli nic innego jak funkcja, która realizuje konkretne zadanie.
Jednocześnie jest tutaj kilka elementów, na które chciałbym zwrócić uwagę.
W pierwszej kolejności jednak za komentujemy sobie tego genialnego IFA po
to, aby zobaczyć jak w ogóle to wszystko działa.
Mój serwer jest już tutaj uruchomiony, więc aplikacja działa.
Zatem jeżeli przejdę w tym momencie do niej po to aby wykonać zapytanie na
localhost 3000 API users, to w odpowiedzi otrzymam tutaj status 200 OK.
A jako ciało odpowiedzi została przekazana tablica zawierająca imiona użytkowników.
Jeżeli jednak teraz wprowadzę pewną małą zmianę do naszej aplikacji i zablokuję
dostęp z poziomu minus, no to jak się pewnie łatwo domyślić, odpowiedź, którą
otrzymamy będzie odpowiedzią zawierającą błąd ze statusem 403 Forbidden.
Oznacza to nic innego, że dostęp do tego zasobu został zablokowany, bądź też po
prostu nie masz do niego dostępu ze względu na ograniczone uprawnienia.
Zwróć też uwagę na pewien mały fakt.
Jedyne co zrobiłem to zamieniłem na false, a pomimo tego elementy takie jak status
odpowiedzi oraz jej struktura zostały odpowiednio przygotowane.
Wspomniałem jednak wcześniej, że
odpowiedzialność za takie rzeczy leży po naszej stronie.
Akurat w przypadku wykorzystania
frameworków takich jak message jest rzeczywiście tak jest.
Natomiast na koniec dnia, gdybyśmy pisali aplikację w czystym not, że jest,
musielibyśmy zadbać o całe przetworzenie zapytania oraz przygotowanie odpowiedzi,
uwzględniając w to jej strukturę oraz status.
Zatem bez wątpienia wiele jest nam tutaj
ułatwione, ale jednocześnie jeżeli przywrócimy sobie dostęp do tego endpoint,
to i tak widzimy tutaj, że wykorzystania tzw.
dekorator. I o nich będę Ci mówił nieco później.
Do tego, aby kontrolować dostęp do tej ścieżki.
Oznacza to, że jeżeli teraz ten dekorator będzie usunięty, a pomimo tego będę chciał
zablokować tutaj dostęp, to i tak ktoś, kto nie posiada odpowiednich uprawnień
zostanie dopuszczony do danych, które zwraca ten konkretny endpoint.
Zatem w Twojej odpowiedzialności leży to, aby zabezpieczyć ścieżki albo bezpośrednio
przy konkretnej akcji lub też ewentualnie w przypadku, że jest możesz przypisać
middleware, czy też w tym przypadku gard do całego kontrolera.
W takiej sytuacji, niezależnie od tego, do
której jego akcji będziemy się odwoływać, i tak dostęp zostanie zablokowany.
Jednocześnie, jeżeli raz odblokujemy ten dostęp, a następnie komentujemy też
naszego IFA, to wewnątrz jego, jak widać jest wyrzucony wyjątek o nazwie Not Found
Exception z dodatkową informacją dla użytkownika.
Jeżeli sobie do niego wejdziemy, to jest to nic innego jak specjalna klasa
wbudowana w nas, że jest do tego, aby ułatwić nam wyrzucanie wyjątków.
W tym przypadku załóżmy, że użytkownicy nie zostali znalezienie i tylko zamiast
zwracać wyjątek, będziemy go oczywiście wyrzucać.
I dzięki temu w momencie, gdy przejdziemy sobie teraz do
mnie i spróbujemy to zapytanie wykonać, to jak widzisz mamy tutaj ustawiony
odpowiedni status oraz też odpowiednie ciało odpowiedzi zawierającą bardzo
opisową informację, którą możemy wyświetlić użytkownikowi.
Zatem po raz kolejny mamy tutaj do czynienia z tą obsługą błędów i
ewentualnych sytuacji, które mogą doprowadzić do tego, że zamiast
oczekiwanej odpowiedzi użytkownik otrzymuje jakąś informację, która pozwoli
mu albo naprawić błędy, albo też poinformuje go, że np.
nie ma dostępu do jakiegoś zasobu i nic nie może z tym zrobić.
Załóżmy jednak, że ten dostęp jest tutaj przydzielony.
W związku z tym nasz kontroler tutaj kontaktuje się z warstwą serwisową i
konkretnie odwołuje się do metody Facility, która w tym przypadku zwraca
tablicę stringów pochodzącą bezpośrednio z napisanej tutaj tablicy.
Jednocześnie też normalnie w aplikacji tutaj występuje połączenie np.
z warstwą repozytorium, bądź też
bezpośrednio z modelem, który umożliwia nam interakcję z bazą.
Zatem w tym konkretnym przykładzie, aby
już nie komplikować, tą warstwę, bazodanowe sobie pominiemy, ale oczywiście
będziemy do niej niejednokrotnie wracać, więc na ten moment uznaję, że po prostu
tablica, którą tutaj mamy pełni rolę naszej bazy danych i tym samym możemy
teraz dojść do punktu, w którym w tym przypadku serwis pobiera informacje z bazy
danych, zwraca je do kontrolera, a kontroler zwraca je do użytkownika,
przygotowując odpowiednią strukturę odpowiedzi.
I zasadniczo tak to dokładnie działa po stronie backendu.
Więc mam nadzieję, że przynajmniej na ogólnym poziomie stało się dla Ciebie
jasne, co dzieje się po stronie backendu i w jaki sposób możesz wchodzić w interakcje
z poziomu frontendu z informacjami, które są przygotowywane przez backend.
Oczywiście te wszystkie poruszone do tej pory wątki będziemy sobie odpowiednio
pogłębiać i na pewnym etapie wszystko stanie się dla Ciebie oczywiste.
Tymczasem doszliśmy do końca tej lekcji,
więc dziękuję Ci za uwagę i zapraszam do kolejnej.