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.
W tej sekcji kontynuujemy temat walidacji
danych, a konkretnie przesuniemy się na część backend ową, gdzie zmodyfikowałem
lekko kod w taki sposób, aby uwzględniał tzw.
Data transfer object, czyli detal, który
jest niczym innym jak klasą określającą strukturę danych.
O tym co to dokładnie jest, jak to budować i jak wykorzystywać.
Będziemy jeszcze mówić.
Natomiast na ten moment musisz wiedzieć tylko tyle, że ta klasa pełni dla mnie
rolę aligatora oraz też zwraca odpowiednie błędy w przypadku, gdy one wystąpią.
Zatem nie ma potrzeby, aby np.
pisać tutaj FR i upewniać się, że
zawartość komentarza istnieje i że nie zawiera jakichś dodatkowych danych itd.
W zamian po prostu określam strukturę
informacji, która ma trafić do tego endpoint i następnie mogę ją wykorzystać.
W moim konkretnie przypadku w tym momencie mówimy tylko o jednym polu, ale celowo
wykorzystałem tutaj operator spread do tego, aby przekazać do mojego serwisu
wszystkie informacje, które zostały przesłane na ten endpoint.
Podobnie też w tym miejscu moglibyśmy
zadbać o to, aby zapisać identyfikator oraz wszystkie dane z komentarza.
Teoretycznie wszystko będzie w porządku, zapis jest bardzo elegancki.
W związku z tym przetestujemy sobie tylko, czy rzeczywiście wszystko tutaj działa.
Teoretycznie wszystko jest tutaj w porządku.
Jeżeli jednak spróbujemy tutaj kombinować
lub też przypadkowo po stronie klienta popełnimy błąd, który sprawi, że prześlemy
tutaj dane jakiegoś innego typu, no to otrzymamy odpowiedź.
400 Błędne zapytanie informujące nas o
tym, że właśnie wystąpił błąd oraz dodatkowo mamy tutaj informację o tym, co
w zasadzie się wydarzyło i te dane mogą również zostać zmodyfikowane i dostosowane
do tego, aby wyświetlić je bezpośrednio użytkownikowi.
Zatem poszliśmy tutaj krok dalej w tą walidację, ponieważ nie tylko zadbaliśmy o
to, aby na serwer trafiały dane odpowiedniego typu, ale również o to,
abyśmy zwracali odpowiednią strukturę informacji o błędach.
Wygląda na to, że zrobiliśmy tutaj całkiem
dobrą robotę, tym bardziej, że nawet jeżeli przekażemy tutaj pusty ciąg znaków,
czyli teoretycznie typ się zgadza, ale wartość jest pusta, to również zapytanie
zostanie odrzucone z informacją o tym, że ta wartość pusta być nie może.
Teoretycznie wszystko jest tutaj w
porządku, ale jeżeli jednak będziemy nieco bardziej kreatywni i np.
zamienimy user chyba np.
10, no to może okazać się, że będziemy w
stanie przypisywać komentarze do innych użytkowników.
Jak widzisz, dokładnie tak się stało.
Coś takiego wynika z faktu, że pomimo
tego, że określiliśmy strukturę danych, których spodziewamy się otrzymać, to też
wykorzystaliśmy wszystko co do nas trafiło i zapisaliśmy je w naszej bazie danych.
Oznacza to, że pomimo tego, że zadbaliśmy o odpowiednią walidację i tak nasza
aplikacja posiada pewne luki, które ktoś sprytny może wykorzystać.
W przypadku nas, że jest, naprawienie tego
problemu jest niesamowicie proste, ponieważ wystarczy wykorzystać Validation
pipe i ustawić flagę wait na TODO i w takiej sytuacji wszystko, co nie
zostanie uwzględnione w obiekcie datą zostanie odrzucone.
W rezultacie, jeżeli spróbuje ponownie
dodać ten komentarz, no to na szczęście tym razem pole User ID zostanie odrzucone.
Ale co by było, gdyby okazało się, że to
pole User ID jest zdefiniowane w naszym obiekcie Create Komentator.
Teoretycznie w końcu chcielibyśmy
przypisać identyfikator użytkownika do konkretnego komentarza.
Oznacza to, że w takiej sytuacji nasz Dead
Out tutaj nie zadziała i dane zostaną poprawnie zapisane, więc nic nie stoi na
przeszkodzie, abym tym razem zmienił sobie identyfikator na innego użytkownika.
No i nasza walidacja przestaje działać.
Dlatego z tego powodu za każdym razem, gdy masz do czynienia z dodawaniem bądź
jakąkolwiek edycją danych, to w momencie, gdy Twoja aplikacja będzie już obsługiwać
uwierzytelnienie połączenia, to tak naprawdę będziesz w stanie nawet sprawdzić
prostym efekt, czy identyfikator użytkownika, który wykonuje zapytanie jest
równy identyfikator, który został podany przy tworzeniu komentarza.
Jeżeli coś się tutaj nie zgadza, to
naturalnie możemy poinformować o tym użytkownika.
I tak zresztą nawet w tym momencie się
stanie, no bo oczywiście nie jesteśmy zalogowani, ale zwróć uwagę, że nadal
otrzymaliśmy poprawną odpowiedź o odpowiedniej strukturze.
Oznacza to, że rzeczywiście nasze
zabezpieczenie działa i tylko musimy zawsze wziąć pod uwagę to, czy użytkownik,
który dokonuje jakichkolwiek zmian ma faktycznie po pierwsze uprawnienia.
Jeżeli posiadamy system uprawnień w naszej
aplikacji lub też ewentualnie czy po prostu edytuje swoje zasoby, o ile
oczywiście nie jest uprawniony do tego, aby edytować zasoby innych.
Zatem jeżeli chodzi o walidację danych po stronie serwera, to to oczywiście różni
się od wykorzystanych przez Ciebie narzędzi.
Natomiast musisz pamiętać o tym, aby
kontrolować to co do Ciebie dociera i w jakiej formie, czy te dane przyjmujesz
oraz czy są odpowiedniego typu i też czy osoba, która wykonuje zapytanie ma prawo
wykonywać tą konkretną akcję i też nadpisać ustalone dane.
Dodatkowo też dobrze byłoby przefiltrować szczególnie te pola, które chociażby
zawierają długie pola tekstowe, które umożliwiłyby użytkownikowi np.
wstrzyknięcie jakiegoś niepożądanego skryptu.
Jeżeli chodzi o taką formę zabezpieczeń, będziemy sobie jeszcze o niej mówić,
natomiast po prostu musisz mieć na uwadze fakt, że wszystko, co trafia do Twojej
aplikacji backend owej jest potencjalnie niebezpieczne.
Na koniec dnia jest jeszcze jedna warstwa, której również w tym momencie już nie
będziemy poruszać, ale chodzi o warstwę bazodanowe.
Nie chcę już za bardzo komplikować tego
tematu, tym bardziej, że będziemy o nim jeszcze mówić, ale musisz wiedzieć, że w
momencie zapisywania informacji do bazy danych tam również określamy strukturę
samej tabeli oraz danych, które mogą zostać w niej zapisane.
I teraz przykładowo, jeżeli w tabeli
komend w naszej bazie danych uwzględnimy kolumnę content, no to musimy określić jej
typ wskazujący na to, że możemy przechowywać w niej wartości tekstowe, ale
też warto upewnić się, że ich długość nie jest nieskończona.
Czyli np.
w przypadku komentarza możesz ograniczyć go np.
do 500 znaków i tym samym też zadbać o to, aby użytkownik, które próbuje dodać
dłuższy komentarz został o tym fakcie poinformowany.
Zatem patrząc na naszą aplikację ze strony klienta oraz serwera.
Jak widzisz temat walidacji jest o tyle istotny, że zachodzi w wielu miejscach,
pomimo tego, że tak naprawdę weryfikujemy dokładnie te same dane.
Po stronie frontendu mamy tutaj feedback do użytkownika, a po stronie backendu
musimy upewnić się, że struktura danych jest poprawna oraz że użytkownik ma prawo
zapisywać informacje, które próbuje do niej przesłać.
Z tego wszystkiego robi się tutaj wiele
kroków, tymbardziej, że musimy dbać też o takie szczegóły jak struktura odpowiedzi,
sensowność komunikatów, które wracają do klienta, czy też chociażby struktura
odpowiedzi w momencie, gdy przekazywane dane są poprawne.
W zależności od tego jak przygotujemy całą
tą komunikację będzie zależało to jak łatwo będzie się nam rozwijało tą
aplikację i też jak zadowoleni będą użytkownicy, którzy po prostu będą
informowani o ewentualnych błędach, które sami będą popełniać, bądź też na wypadek
niedostępności naszej aplikacji również zostaną o tym stosownie poinformowani.
Mam nadzieję, że to wszystko jest dla
Ciebie zrozumiałe, ale oczywiście jeżeli chodzi o szczegóły i praktykę będziemy
sobie jeszcze do tego niejednokrotnie wracać.
A teraz z mojej strony to wszystko, więc zapraszam Cię do kolejnych materiałów.