w Praktyce
10 godz. 44 min · Node.js · Full-stack i Programowanie
Piotr PalarzWeb DeveloperW kursie tym poznasz platformę Node.js od podstaw, aż po bardziej zaawansowane koncepcje. Zaczniemy od omówienia czym jest Node, a także jakie może być zastosowanie tej technologii. Następnie przejdziemy przez proces instalacji i napisanie swojego pierwszego skryptu. Już na samym początku dokładnie omówimy tworzenie własnych modułów, gdyż jest to wiedza niezbędna, by dobrze zrozumieć funkcjonowanie Node. Następnie dowiesz się czym są zdarzenia, jak działa model “publish / subscribe”, a także czym jest “event-driven development”. Chwilę później omówimy pracę z buforami, stream’ami, a także ze standardowym wejściem i wyjściem. Ta wiedza pozwoli Ci zrozumieć jak tworzone aplikacje mogą otrzymywać od użytkownika dane oraz jak je wyświetlają.
Niezwykle ważnym rozdziałem będzie ten, poświęcony pracy z systemem plików. Szczególnie dla dewelopera, pracującego dotychczas z językiem JavaScript wyłącznie w środowisku przeglądarki internetowej. Node pozwala bowiem tworzyć nowe pliki, zapisywać w nich dane oraz odczytywać i usuwać pliki i katalogi. Przy wszystkich tych operacjach, niezwykle ważna jest jednak asynchroniczna natura Node. Dowiesz się jak działa, a także jakie są jej zalety. Na tym etapie nie zabraknie oczywiście praktycznego projektu, którym będzie aplikacja typu CLI (Command Line Interface). Pozwoli nam ona grupowo zmienić nazwy wielu plików, według podanego wzorca.
W kolejnym rozdziale poruszymy fundamentalną dla Node kwestię, mianowicie tworzenie serwerów sieciowych. Zaczniemy od najniższego poziomu, tworząc prosty serwer bazujący na protokole TCP/IP. Wiedza w jaki sposób Node radzi sobie z takim zadaniem, pozwoli później lepiej zrozumieć wyższe warstwy, takie jak np. HTTP czy WebSockets. Chwilę później stworzymy swój pierwszy serwer HTTP, do którego będzie można wysyłać zapytania wprost z przeglądarki internetowej. Omówimy również jak w Node wykorzystać bezpieczne szyfrowanie HTTPS.Na tym etapie będziesz już miał solidną wiedzę jak pracować z Node, jednak zanim przejdziemy dalej, zatrzymamy się, by omówić jak dokładnie działa Node.js, a także jak ta platforma została zbudowana. Dwie dość obszerne lekcje, będą być może jednymi z najważniejszych w tym kursie. Dowiesz się w nich czym jest, a także jak działa jednowątkowa pętla zdarzeń, czym jest proces i wątek, a także zobaczysz kod źródłowy Node.js i wszystkie bloki budulcowe, z jakich Node się składa. To naszym zdaniem niezwykle ważny temat, często jednak pomijany w wielu materiałach. Dzięki dogłębnemu zrozumieniu jednowątkowej natury języka JavaScript i asynchroniczności Node, będziesz mógł tworzyć dużo lepsze aplikacje.
Node.js posiada kilkanaście wbudowanych modułów, z których w dowolnej chwili można skorzystać. Wszystkie jednak dają nam dużą, niskopoziomową kontrolę, ale czasami sporo kodu należy napisać, by zrealizować jakieś zadanie. Jest to jednak świadomy wybór twórców Node, gdyż całą resztę świetnych rozwiązań, dopisuje nieustannie ogólnoświatowa społeczność deweloperów. Zdecydowana większość z modułów ląduje w rejestrze npm. Jest to genialny package manager, który pozwoli nam wyszukiwać, pobierać i aktualizować niezliczoną ilość modułów. Dowiesz się zatem jak korzystać z npm, a chwilę później zaczniemy wykorzystywać zgromadzone tam moduły w dalszej pracy.Jednym z najpopularniejszych modułów jest express.js, który pozwala w bardzo prosty sposób tworzyć serwery HTTP. Grzechem byłoby zatem z niego nie skorzystać. Dowiesz się wszystkiego co niezbędne, by zacząć tworzyć własne aplikacje bazujące na protokole HTTP z użyciem express.js, a także kilku dodatków do tego systemu. Zobaczysz jak routować zapytania, jak korzystać z middleware czy serwować statyczne pliki. Następnie omówimy współpracę z bazą danych MongoDB i z jej wykorzystaniem stworzymy API typu REST. Stworzona aplikacja pozwoli odczytywać dane z bazy i przesyłać je do klienta w formacie JSON, a także dodawać nowe dane, aktualizować i usuwać je. Wszystko to zgodnie z dobrymi praktykami pracy z REST.
Chwilę później czeka Cię kolejny praktyczny projekt - skracacz linków. Stworzymy wspólnie aplikację, która pozwoli skrócić dowolny adres URL do krótkiej formy. Oczywiście będzie działać również w drugą stronę! Kiedy przejdziemy pod skrócony adres, przekieruje nas do odpowiedniej witryny. Node.js to platforma wręcz stworzona do tworzenia aplikacji typu real-time, dlatego w kolejnym rodziale podejmiemy temat technologii WebSockets. Dowiesz się jakie są jej zalety, a także jak pracować z nią po stronie serwera i klienta. Tutaj czeka nas kolejny praktyczny, niezwykle ciekawy projekt. Wykonamy bowiem czat grupowy. Aplikacja ta pozwoli dowolnej ilości użytkowników podłączyć się do czatu podając swój nick, a następnie wysyłać widoczne dla wszystkich wiadomości. Zaimplementujemy nawet takie rozwiązania jak wyświetlanie statusów o dołączeniu kogoś do czatu, a także o jego opuszczeniu.W przedostatnim rodziale tego kursu podejmiemy tematykę dobrych praktyk pracy z Node.js. Na początku omówimy najważniejsze konstrukcje nowej specyfikacji EcmaScript 2015, które są znakomicie wspierane w Node. Chwilę później omówimy jak korzystanie z Promises uprości, a także ulepszy nasz kod. Wśród dobrych praktyk nie zabraknie również informacji o debugowaniu aplikacji. Zobaczysz sprawdzone sposoby, by znaleźć błędy lub lepiej, krok po kroku, zrozumieć jak działa napisany wcześniej kod. Dowiesz się również jak pracować z błędami, by Twoje aplikacje działały w sposób przewidywalny.
Ostatni rozdział w całości został poświęcony temu, co zwykle jest pomijane w innych materiałach, mianowicie wdrażaniu aplikacji do produkcji. Przez cały ten kurs pracować będziemy lokalnie, lecz kiedy aplikacje są już gotowe, wypadałoby udostępnić je światu. Wdrażanie aplikacji napisanych z użyciem Node.js nie jest jednak tak oczywiste, jak np. wgrywanie WordPress’a u wybranego hostingodawcy. Ty będziesz miał jednak możliwość zobaczyć, jak wdrożyć napisany przez nas grupowy czat na platformie Heroku. Jest to bardzo popularny serwis działający jako PaaS (Platform as a Service). Za darmo będziesz mógł w ciągu kilku chwil uruchomić swoją aplikację.Zobaczysz o co należy zadbać, by wszystko poszło gładko. Serwisy typu PaaS dbają o bardzo wiele aspektów wdrażania i serwowania naszych aplikacji, takich jak bezpieczeństwo oraz nieustanną dostępność. Mają jednak pewne ograniczenia. Z tego powodu, dowiesz się również jak wdrożyć swoją aplikację na serwerze wirtualnym VPS z systemem Ubuntu Server. Takie rozwiązanie daje nam całkowitą kontrolę, ale także obarczone jest większą odpowiedzialnością. Zaczniemy od instalacji na serwerze platformy Node.js, systemu kontroli wersji GIT, a także innych niezbędnych modułów
Następnie zobaczysz jak skonfigurować swoje lokalne środowisko tak, by za pomocą GIT’a wysyłać kod do zdalnego serwera, a potem jednym poleceniem wdrażać go do produkcji. Dowiesz się również jak jednocześnie serwować wersję produkcyjną oraz developmencką. W rodziale tym poruszymy również inne kwestie, takie jak procesy potomne czy tworzenie klastrów. Dzięki tej wiedzy, będziesz mógł maksymalnie wykorzystać dostępne zasoby serwera. Na sam koniec tego kursu rzucimy okiem również na inne, nie przedstawione wcześniej zastosowania Node, a także nakreślimy dalszą drogę nauki w tym zakresie.
Kurs ten jest dla wszystkich osób, które dobrze czują się w technologiach frontendowych, tj. HTML, CSS i JavaScript, a teraz chcą rozpocząć swoją przygodę z back-endem. Im zatem lepiej znasz język JavaScript, tym więcej wyciśniesz z Node, natomiast nie jest wymagana bardzo zaawansowana wiedza z zakresu tego języka.
W tej lekcji opowiem ci o tym, czym jest REST, a także jak możemy stworzyć takie API z użyciem Expressa.
Ja już poczyniłem pewne kroki tutaj na samym początku i mamy taką oto aplikację, dlatego wystarczy, że w
katalogu 32 zainstalujemy sobie wszystkie moduły z pliku package.json. Wciskam Enter, wpisując wcześniej
npm install. I będziemy mogli uruchomić sobie serwer z użyciem nodemona. Ok.
Serwer został uruchomiony i po odświeżeniu zauważ, mamy coś takiego jak lista użytkowników.
I tutaj nam się wyświetlają wszyscy użytkownicy po kolei.
Skąd to się wzięło?
Otóż przejdźmy sobie do edytora Sublime Text.
I ty będziesz startował razem ze mną z taką aplikacją.
Czyli tu na razie nie ma nic, czego byś nie znał.
Natomiast w miejscu, w którym robimy render i przekazuję title "Lista użytkowników", który się wyświetla
tutaj, przekazuję również tablicę z tymi nazwiskami.
I teraz skąd ona się wzięła?
Otóż odwołałem się do users -
w tym miejscu - list i chcę to przekazać pod users.
Skąd to się z kolei wzięło?
To jest API, które napisałem wcześniej, i na samej górze go inkluduję jako zewnętrzny moduł.
Czyli tutaj będzie jakiś obiekt zawierający metodę list.
Ona zwróci jakąś tablicę i ją przekaże tutaj. Ten widok home będzie się znajdował tutaj w views - home.handlebars.
I zauważ, że tutaj w handlebars sprawdzam if, czy mamy jakąś tablicę. Jeżeli tak, to w ul chcę to wszystko wyświetlić
za pomocą metody each -
each users.
I możemy się później odwołać do name czy lastname,
a także tutaj robię data-id równa się id.
Nie będzie nam to potrzebne, ale później powiem ci, o co w tym chodzi. Więc wyglądałoby to w ten sposób.
To jest wygenerowane.
Ok.
Czyli na razie nic dla ciebie nowego.
Zanim jednak przejdziemy dalej, to będę chciał ci szybciutko wytłumaczyć, co zrobiłem w tym module users,
co tam się dzieje. Więc przejdziemy sobie do tego katalogu users i tutaj.
I zauważ, że na samym dole eksportuję sobie module.exports
takie pięć metod, czyli add, get, update, delete oraz list.
No i właśnie z list skorzystaliśmy tutaj. Z reszty skorzystamy za moment. Users.list to jest właśnie
ta funkcja.
Czyli to jest listusers.
Skąd ona się wzięła - jest tutaj - i co ona robi?
Zwraca nam users -
to jest na samej górze - skopiowane, czyli poprzez metodę copy.
Co to jest z kolei users?
Otóż na samej górze, jak widzisz, oprócz modułu file system i path zrobiłem sobie jeszcze require usersDb.
A usersDb jest to plik json, który utworzyłem wcześniej i wygląda następująco.
Czyli mamy tutaj taką jakby bazę danych z użytkownikami. Wiesz już, że funkcja require nam taki plik json wczyta
i zapisze nam go pod zmienną jako pełnoprawny obiekt JavaScript.
Czyli w tym przypadku będzie to tablica z tymi użytkownikami. A więc metoda list, z której skorzystaliśmy,
zwraca po prostu users.
Ale żeby mi nie zwracało tego obiektu, gdybym tutaj gdzieś skorzystał z users.list, to miałbym obiekt, w zasadzie
tablicę, a bym nie mógł tutaj nic zmodyfikować w tej tablicy, bo referencja do niej zostałaby zwrócona.
To otworzyłem sobie jeszcze metodę copy, która jest na samej górze.
I ona polega na tym, że jeżeli przekażemy jej jakiś obiekt, w tym przypadku tę tablicę, to JSON.stingify
zamieni nam ten obiekt na string - taki jsonowy - a później z powrotem JSON.parse zamieni nam to na pełnoprawny
obiekt i zwróci, ale będzie to już kopia tego obiektu.
Dzięki temu jeżeli tutaj skorzystam z users.list, to mogę sobie dowolne rzeczy tam modyfikować i nie zmodyfikuję
tak naprawdę obiektu, który mam zapisany tutaj.
Jak możesz zobaczyć, jest tutaj jeszcze więcej metod.
Te metody będą nam służyć do operacji CRUD, czyli create, read, update, delete.
Są to operacje, które wykonujemy na bazie danych zazwyczaj, i które są niezbędne dla API typu REST.
Jak zatem widzisz, stworzyłem sobie jeszcze kilka metod, które pozwolą nam dodawać nowego użytkownika,
pobierać użytkownika o danym ID,
aktualizować takiego użytkownika i usuwać.
I każda z tych metod,
co jest ciekawe, to w którymś momencie wykonuje save. Czyli coś zmieniamy - polecam ci, abyś ten plik dokładnie sobie przejrzał -
i potem wykonujemy save. A w funkcji save zrobiłem po prostu coś takiego, że jeżeli coś zmienimy na tym obiekcie,
który mamy tutaj wczytany - users - to chcę za pomocą save zapisać ten obiekt poprzez JSON.stringify.
Tutaj podaję null i 4, żeby to ładnie sformatować i zapisać to z powrotem do pliku usersDB.json.
Jeżeli zatrzymamy sobie taki serwer i uruchomimy go od nowa, od nowa ten plik będzie parsowany i wczytywany,
to mamy pewność, że w nim wcześniej to wszystko zostało zapisane, dlatego że w każdej z tych metod korzystam
sobie po jakiejś operacji z save, aby ten obiekt po prostu wrzucić z powrotem do pliku.
usersDB.json.
Nie będę już tłumaczył wszystkiego, co jest w tym pliku.
Masz go u siebie, więc dokładnie sobie go przeanalizuj.
Nie jest on skomplikowany.
Generalnie pozwala nam wykonywać wszystkie te operacje, o których mówiłem.
A to, co eksportujemy, to właśnie te metody add, get, update, delete oraz list. Z jednej z nich skorzystaliśmy - jest to list.
Natomiast teraz będę chciał skorzystać z wszystkich pozostałych, tworząc API typu REST.
Chciałbym, żeby nasze API było dostępne pod adresem /api, więc skopiuję sobie tego get i napiszę tutaj
api i następnie np. users.
I nie chcę nic renderować, ale chcę pobrać sobie tych wszystkich użytkowników tak jak tutaj i następnie
ich odesłać.
Dlatego teraz pokażę ci bardzo ciekawą metodę Expressa. Res i zamiast send czy render skorzystamy
z json.
Jest to metoda, która pozwala nam wstawić tutaj obiekt JavaScript.
Możemy tutaj wpisać, co chcemy i to zostanie zamienione na json i przesłane dalej w taki sposób, że
również odpowiednie nagłówki typu content type: application/json zostaną ustawione.
Dlatego tutaj będę chciał przekazać to, co zwróci mi users.list, czyli tablicę z wszystkimi tymi użytkownikami.
No i tyle wystarczy. Jeżeli teraz przejdziemy pod api/users,
to zauważ, że json z wszystkimi użytkownikami został nam zwrócony i dokładnie o to nam chodziło.
Gdybyś podejrzał nagłówki, tak jak wspomniałem, wszystko będzie poprawnie przez Express ustawione.
Teraz chcę skorzystać z kolejnej ścieżki, która będzie nam potrzebna do naszego API.
Będzie to get i user/id.
Pamiętasz, że możemy takie parametry tworzyć w Expressie i teraz mamy metodę, o której ci mówiłem tutaj
get. To jest getUser. GetUser stworzyłem w ten sposób, że pozwala nam ona podać ID i zwróci nam użytkownika
o takim ID, który zostanie znaleziony tak naprawdę w tym pliku, który wcześniej był wczytany do pamięci.
Czyli podamy np. id 3 - zwróci nam Tomasza Janickiego. Dlatego teraz tutaj będę chciał się odwołać do users.get
i przekazać tutaj to ID.
ID sobie sczytamy z req.params.id - już ci to również pokazałem.
Czyli to będzie to. Dlatego jeżeli teraz przejdziemy pod user wpiszemy 3, to Tomasz Janicki został
nam zwrócony. Czyli na razie wszystko jest w porządku.
Teraz jednak przejdziemy do tego, co tak naprawdę będzie istotą API typu REST. Wytłumaczę ci, jak to działa.
Zauważ, że do tej pory za każdym razem wpisywaliśmy app.get, ja szczególnie nie tłumaczyłem,
co to oznacza.
Mianowicie oznacza to, że chcemy tę funkcję wywołać dla każdego połączenia pod taką ścieżką, ale musi
to być połączenie, które wykorzystuje metodę http get.
Ważne jest, aby rozumieć, że mamy kilka różnych metod http.
Najpopularniejszą jest get, ale na drugim miejscu mamy również metodę post.
Za każdym razem, i to możemy zobaczyć, przychodząc do Network,
Kiedy przechodzimy na dowolną stronę w internecie, wpisując adres w przeglądarce, wciskając Enter, to przeglądarka
wysyła zapytanie o metodzie get pod localhost. I następnie pobrała sobie pliki css czy jeden plik css - również
metodą get.
Gdybyśmy na tej stronie mieli formularz, np. logowania, to zazwyczaj jeżeli wysyłamy taki formularz i
nie widzisz, żeby jego dane zostały tutaj do query stringu dopisane, to jest on wysyłany metodą typu post.
To są dwie najpopularniejsze metody. Natomiast protokół HTTP ma jeszcze kilka innych metod, takich jak
np. put, która służy do aktualizowana czegoś na serwerze i delete, która służy do usuwania.
Natomiast należy zrozumieć, że samo wysłanie zapytania o typie delete, nie sprawia że serwer coś usunie.
My na serwerze musimy zdecydować, co chcemy z tym zapytaniem zrobić.
No i właśnie zawsze wpisując app.get, mówiliśmy, że ma to być typ get. Czyli gdybyśmy pod ten adres wysłali
zapytanie post, to Express nie zwróciłby nam tej strony.
Natomiast Express posiada również taką metodę jak all i ona obsłuży tę funkcję dla każdego zapytania
pod tą ścieżką.
Natomiast może to być zapytanie typu get, post itd.
Zostawimy tutaj get, ale mówię ci o tym dlatego, że teraz chciałbym, abyśmy stworzyli sobie ścieżkę, która
będzie służyć do aktualizacji takiego pojedynczego użytkownika. Dlatego skopiuję to, co mamy w tym miejscu.
I adres będzie dokładnie ten sam, ale zamiast get napiszemy put. W ten sposób Express wywoła tę funkcję,
jeżeli pod taki adres wyślemy zapytanie o metodzie HTTP put. Zauważ, że adres jest dokładnie ten sam.
I właśnie to jest istota API typu REST, że mamy dokładnie taki sam adres np. do pobierania pojedynczego
użytkownika, ale taki sam będzie do jego aktualizacji i usuwania.
Natomiast żebyśmy mogli go zaktualizować, to będziemy potrzebowali jakichś danych i będziemy chcieli
je przekazać do specjalnej metody, którą stworzyłem tutaj. Jest to updateUser. Przekazujemy userData
i zostanie to odpowiednio zaktualizowane. I ta metoda tutaj nazywa się update. Co jest jeszcze ważne, to na końcu
robię zawsze coś takiego, że zwracam takiego użytkownika, czyli jeżeli go sobie zaktualizujemy, to na końcu go również
zwracam.
Dlatego ta metoda update zwróci nam go i będziemy go mogli odesłać. Z tego powodu możemy wpisać od razu
users.update, przekazać tutaj nowe dane. No właśnie, skąd je weźmiemy? Zaraz ci pokażę.
I wtedy on zostanie zaktualizowany po tej stronie, zapisany do pliku i zwrócony. I będziemy go mogli json-em odesłać.
Bo to również jest dobra praktyka w przypadku API typu REST, że jeżeli zaktualizujemy jakieś dane, to chcemy,
aby zostały do nas odesłane i możemy sobie je np. na stronie wyświetlić z użyciem JavaScript po stronie
klienta czy np. z użyciem aplikacji mobilnej - dlatego że z takich API restowych również aplikacje mobilne
bardzo mocno korzystają. Na tym etapie będziemy potrzebowali specjalnego middleware, które ci zaraz pokażę.
Natomiast dlaczego?
Otóż jeżeli wysyłamy zapytanie typu get, to jedyne dane, jakie możemy przekazać, to są w takim query stringu.
Możemy sobie tutaj coś wpisać i możemy po stronie serwera to odczytać.
Natomiast jeżeli wysyłamy zapytanie typu post, takie jakim przesyłamy np. dane z formularza, to takie zapytanie jest
wysłane do serwera i oprócz tego, że oczywiście ma adres URL, to posiada jeszcze body. I w tym body są
wszystkie dane wpisane w takim formularzu. I zapytanie typu put również pozwala przesyłać takie body.
Czyli będziemy chcieli zaraz wysłać takiego puta, pokażę ci jak, a w nim przekazać nowe dane do zaktualizowana
pod ten adres.
Czyli jeżeli wyślemy to pod adres users 3, czy user a id 3, wcześniej jeszcze api, to jest zapytanie typu
get, które nam go zwraca, jak widzisz. Ale jeżeli pod ten sam adres wyślemy nowe dane, to chcę tam przesłać
np. name równa się Tomek, lastname równa się Janicki i wtedy go zaktualizować. Czyli abyśmy te dane mogli przesłać,
to potrzebujemy po stronie serwera jakoś je sparsować i możemy to zrobić za pomocą specjalnego middleware, dzięki
któremu pod req.body będziemy mieli to, co zostanie przesłane z takim zapytaniem. Będziemy musieli
sobie je zainstalować, dlatego zatrzymam serwer i wpiszemy npm
install body-parser i save,
aby zapisać go do pliku package.json. Ok. I teraz możemy z powrotem uruchomić serwer, a na samej górze
ten body parser będę chciał sobie zainkludować.
W ten sposób.
Teraz jest to middleware, więc musimy go użyć za pomocą app.use, dlatego on będzie używany dla każdego zapytania.
Jak to zrobić?
App.use i następnie bodyParser.
I tutaj musimy wybrać metodę, jaką chcemy parsować
to, co będzie w body. My chcemy to robić za pomocą json.
Natomiast na stronie body parsera znajdziesz również inne metody, np. urlencoded.
W ten sposób. I tak będziemy parsować zazwyczaj, jeżeli dane są wysyłane ze standardowego formularza, np.
logowania.
Tak się dzieje zazwyczaj np. na serwerze PHP, natomiast my tutaj mówimy: json, a to oznacza, że dla każdego
zapytania sprawdź, czy ma ono body.
Jeżeli tak, to ten tekst, który się tam znajdzie, spróbuj sparsować json-em.
Jeżeli się uda, to pod req.body
zapisz nam to, co się tam znalazło.
Dzięki temu będziemy tutaj pod req.body mieli sparsowaną treść czy body
takiego zapytania. To właśnie req.body będziemy mogli przekazać do metody update, która tutaj wymaga tego
userData. Zaraz sobie jednak jeszcze wyświetlimy je w konsoli, ale to req.body
chciałbym, żeby posiadało również ID, które zostało przekazane w tym miejscu. Bo zauważ, jak wygląda ta
metoda. Ona przyjmuje userData i w tym userData wyszukuje sobie ID i za pomocą tego ID właśnie metodą
findUserById, którą stworzyłem, go wyszukuje.
Czyli to ID chcemy tam dodać, dlatego napiszę req.body.id równa się req.params.id.
Wiemy, że req.params nam zwróci to ID właśnie z tego URL-a, więc chcemy je tam dodać i dopiero później to req.body przekazać
dalej.
Natomiast zanim to zrobimy, to chciałabym tutaj zrobić res.send pusty ciąg znaków, a w konsoli wyświetlić sobie
req.body - nawet zanim dodamy to ID.
W ten oto sposób. No i teraz najważniejsza rzecz. Otóż w jaki sposób wysłać zapytanie typu put, skoro w
przeglądarce nie wiemy, jak to zrobić?
Teraz pobierzemy sobie taki programik, który nazywa się Postman.
Możesz go znaleźć tutaj.
A zatem w Chrome Web Store wyszukaj sobie po prostu Postman i będziesz mógł taką aplikację tutaj zainstalować.
Ja już to wcześniej zrobiłem, więc mogę ją po prostu uruchomić.
Ona się instaluje jako taki osobny programik w naszym systemie operacyjnym, który można uruchamiać. Ta aplikacja
wygląda następująco.
Otóż pozwala nam wysyłać różne typy zapytań.
Mówiłem ci, że jest ich więcej.
No i właśnie tutaj widzisz całą listę.
Najpopularniejsze to get czy post, ale mamy również put albo delete. My z tych dwóch będziemy jeszcze korzystać,
bo API typu REST korzystają właśnie z put, delete, post oraz get.
Zobaczmy, co stanie się, kiedy wyślemy get pod ten adres. Klikam send.
No i, jak widzisz, został dla nas zwrócony
ten kod HTML, czyli to samo, co otrzymuje przeglądarka.
Natomiast jeżeli przejdziemy pod api/users - w ten sposób - wyślę takie zapytanie, to już json zostanie
dla nas zwrócony, bo tak sobie skonfigurowaliśmy nasze API i w Headers możemy zobaczyć, że Express ustawił
np. content type na application/json, więc wszystko jest w porządku. Jeżeli wyślemy zapytanie pod user,
np. 3, typu get, to zostanie zwrócony ten
Tomasz Janicki. A teraz ja chciałbym wysłać zapytanie typu put pod user 3 i mówiłem ci, że musimy tam
przesłać body. Body możemy wpisać w tym miejscu, w tej zakładce tutaj raw,
i wpiszemy sobie to jako taki oto obiekt. Mieliśmy tam name, pamiętasz Tomasz Janicki,
więc zmieńmy sobie to na
Tomek. Janicki nawet nie muszę podawać, bo ja w ten sposób napisałem sobie naszą aplikację. Gdybyśmy zerknęli do
users, że aby updateUser oczekuje, że przekażemy jakiś obiekt i następnie wszystkie klucze tego obiektu czy wszystkie
dane, które są w tym obiekcie, będzie łączył z obiektem, który podamy sobie w Object.assign. Object.assign
w JavaScript pozwala nam podać jeden obiekt i kolejny obiekt i od prawej do lewej ich właściwości
będą łączone. Czyli np. jeżeli tutaj w userData name to będzie Tomek, bo takie coś wyślę, a tutaj w user będziemy
mieli name - Tomasz, lastname - Janicki, to właśnie to name Tomek zastąpi name tutaj i zostanie to dopiero później zwrócone.
W zasadzie to obiekt user zostanie zmodyfikowany i ten obiekt user później będziemy mogli tutaj zwrócić.
Zatem aby do tej metody updateUser przekazać userData - zrobiłem to w tym miejscu,
ale jeszcze zaraz sobie do tego przejdziemy - to musimy to mieć. I mamy to pod req.body.
Co pokazałem ci tutaj.
Kiedy wyślemy takie zapytanie, czyli teraz to zapytanie chcę wysłać, ale chciałbym jeszcze w headers dopisać, że
wysyłamy zapytanie, które przesyła treść o content type application/json - w ten sposób. I wyślemy takiego
puta, zobaczmy, co się stanie.
Jak widzisz, nic nie zostało odesłane, bo zrobiłem właśnie send pusty ciąg znaków, ale w konsoli powinno to zostać
wyświetlone. I dokładnie tak się stało, czyli name: Tomek. Po to był nam potrzebny
cały ten bodyParser, żeby właśnie z każdym zapytaniem wykonać middleware, które spróbuje to body przesłane,
czyli tekst, sparsować jako json.
My ten tekst dokładnie przysłaliśmy w tym miejscu i zostało to sparsowane jako json.
Dzięki temu mam do tego dostęp pod moim API w req.body i nie jest to żaden tekst.
Jest to normalny obiekt JavaScript, w którym będziemy mieli Tomek pod kluczem name.
Teraz to będę chciał przekazać dalej, bo ta metoda tego wymaga, dodając jeszcze wcześniej ID, które sczytałem
sobie stąd, bo tego ID nie przesyłaliśmy.
I teraz powinno nam to bez problemu już zadziałać.
Wyślijmy raz jeszcze takie zapytanie i jak widzisz, z powrotem został nam odesłany obiekt zmodyfikowany już
Tomek Janicki. To znajdziesz dokładnie w tej metodzie updateUser, którą stworzyłem.
Jeżeli będziemy chcieli to zmienić z powrotem na Tomasz, to przesyłamy i zostało to zmodyfikowane.
To co jest ważne, to gdybyś zerknął do pliku usersDB,to również za każdym razem jest to zapisywane za pomocą funkcji
save.
W ten sposób możemy dokończyć tworzenie naszego API już trochę szybciej.
Mianowicie mamy put do aktualizacji.
Teraz będę chciał delete stworzyć, które będzie usuwać. Ono jest bardzo proste, dlatego że będziemy wysyłać zapytanie
o typie delete, a więc mamy taką metodę na Express jak delete pod takiego właśnie URL-a. Czyli dokładnie
to jest cały czas ten sam adres URL, ale różni się tylko rodzajem zapytania, czyli metodą HTTP,
jak możesz zobaczyć. I tutaj skorzystamy sobie z users.delete, czyli z metody, którą stworzyłem, i przekażemy to
w ten sposób. Korzystamy z niej, ona usunie takiego użytkownika, zapisze ten plik json i go zwróci w
to miejsce, dlatego możemy go za pomocą res.json odesłać. Czyli zerknijmy. Mamy takiego użytkownika jak
Natalia Słowik o ID 5.
Spróbujmy ją sobie usunąć. Przejdziemy pod ID 5. Najpierw get, Natalia nam się tutaj pokazała, a teraz wyślę
zapytanie o typie delete. Wysyłam.
Natalia została zwrócona, bo również tak to napisałem, aby nam to zwracało.
Natomiast jeżeli teraz przejdziemy do get > user 5, zostanie zwrócone null. A gdybyśmy przeszli po prostu
pod users, wszyscy zostaną zwróceni, ale nie będzie tam już Natalii.
I dokładnie tak samo byłoby w przeglądarce, gdybyśmy sobie tutaj wrócili do tej strony głównej, gdzie mieliśmy
wszystkich użytkowników zwracanych.
Nie ma tutaj już Natalii. Jeżeli na tym etapie jednak nie do końca rozumiesz, dlaczego wysyłamy z jakiegoś
Postmana takie zapytania, a jak to możemy robić w inny sposób, to chcę cię tylko uspokoić, że spokojnie gdybyśmy sobie tutaj zaimplementowali
w jQuery wysyłanie Ajax-ów, czyli powiedzmy moglibyśmy kliknąć na takiego użytkownika, przejść pod
jego adres, mieć jakiś formularz do jego edycji itd, to w momencie kiedy kliknęlibyśmy Edytuj, to moglibyśmy wysłać
zapytanie Ajax do naszego serwera. I w zapytaniach
Ajax możemy zdefiniować metodę. Czyli mogłoby to być zapytanie o metodzie, np. put i wtedy zostałby
on zaktualizowany.
Natomiast aby uprościć ten przykład, to robimy to z pomocą takiego Postmana, który jest świetny do właśnie
testowania takich aplikacji.
Mamy zatem już prawie wszystkie metody. Teraz będę chciał jeszcze tylko dodać metodę, która pozwoli nam
dodawać nowego użytkownika. I będzie to metoda, która będzie się nazywać post.
Może ja zrobię ją nawet w tym miejscu.
Czyli mamy post.
To będzie przyjmować zapytanie
post pod api/users. Czyli znowu -
w jaki sposób działa API typu REST?
Jeżeli mamy pojedynczego użytkownika, to mamy właśnie taką ścieżkę, czyli user/id zarówno do pobierania
o nim danych do aktualizacji i do usuwania. Jeżeli chcemy pobrać wszystkich, to mamy api/users.
Natomiast jeżeli chcemy dodać nowego, to również dodajemy to pod /users. To jest taka dobra praktyka,
aby właśnie pod takie URL-e kierować.
No i właśnie będziemy chcieli wysłać tutaj post. I w tym poście będziemy chcieli znowu przekazać dane takiego
nowego użytkownika, więc znowu przyda nam się tutaj bodyParser.
Natomiast skorzystamy z metody, która nazywa się add. Tutaj na końcu ją sobie eksportuję, czyli users.add.
I dokładnie w ten sam sposób jak w przypadku put, będę chciał tam przekazać req.body, które będzie
sparsowane za pomocą bodyParsera i powinno nam to zadziałać.
Jeżeli chcesz zobaczyć jak ta metoda działa z drugiej strony, to zerknij do users.js. Więc przejdziemy do Postmana.
Pamiętaj, że typ to będzie post pod ukośnik właśnie users i będziemy chcieli w body przesłać sobie dane
takiego nowego użytkownika, czyli np. będzie to name Maciej i następnie lastname powiedzmy Zieliński.
Pamiętaj, że to, co tutaj wpisujemy, tak naprawdę jest przesyłane jako zwykły tekst w body takiego zapytania
i po stronie serwera dopiero jest parsowane
właśnie tym bodyParserem. Wyślijmy. Zobacz, że Maciej Zieliński został dla nas zwrócony i dostał on nowe ID.
My tego ID nie podaliśmy, ale odesłaliśmy go z takim ID.
I to jest kolejna dobra praktyka w przypadku tworzenia API typu REST.
Jeżeli wysyłamy jakieś dane - je moglibyśmy wysłać przecież z formularza na stronie - to chcemy, aby nam serwer
odesłał po dodaniu do bazy danych takiego użytkownika czy takich danych, aby nam go odesłał razem z przydzielonym
ID.
To ID przydzielam sobie - możesz zobaczyć - w users add, czyli tutaj za pomocą getNextId.
Napisałem sobie taką metodę pomocniczą. Ona jest bardzo prosta. Otóż w tej tablicy zwracamy sobie ostatni
element.
Sprawdzamy, jakie ma ID, i do tego dodajemy po prostu jeden.
Jak zatem widzisz, ten Maciej Zieliński został tutaj dodany do tego pliku i zapisany. Tym prostym sposobem
stworzyliśmy sobie API typu REST, które pozwala nam dodawać, usuwać czy aktualizować użytkowników w taki
właśnie sposób.
Tylko że po drugiej stronie nie mamy bazy danych, ale to wszystko zapisujemy do pliku. W lekcji kolejnej
pokażę ci, jak pracować z bazą danych.
Natomiast ostatnia rzecz, którą chcę zrobić w tej lekcji, to pokazać ci, jak w Express działa osobny router.
Dlatego będę chciał sobie teraz utworzyć nowy katalog, tutaj gdzie jesteśmy - w 32.
Nazwiemy go api. I w nim będę chciał utworzyć plik api.js. Tutaj będziemy potrzebowali dwóch rzeczy. Mianowicie
Expressa - dlatego sobie go importuję - i users, czyli tego, co importowałem w tym miejscu.
Zauważ, że ścieżka jest inna. Tutaj mieliśmy po prostu users, bo było to w tym samym katalogu, co plik index,
natomiast api jest już tutaj. I plik api.js żeby się odwołać do users, to musi podać właśnie taką oto
ścieżkę.
Dlatego mówiłem ci o tym, że jeżeli podajemy na różnych stopniach zagnieżdżenia różne ścieżki, to moglibyśmy
podać po prostu users, a cały nasz katalog users wrzucić do node_modules. Wtedy zostałby bez problemu znaleziony.
Ale te dwie rzeczy będą nam potrzebne i teraz będę chciał utworzyć za pomocą Expressa nowy router. Zrobimy
to, wpisując const router i następnie express.router. Teraz przejdziemy sobie do naszego pliku -
tutaj coś wpisałem źle - index i wytnę stąd całe API, które stworzyliśmy. Czyli ten plik chcę, żeby był odpowiedzialny
wyłącznie za wyświetlanie tego HTML-a, który mieliśmy od samego początku
pod takim adresem. Ten HTML będzie wyświetlany, ale nic więcej nie chcę mieć w tym pliku.
Dlatego wszystko wkleję w tym miejscu.
I teraz każde wystąpienie app zamienię sobie na po prostu router.
W ten sposób. I teraz na końcu będę chciał z tego modułu wyeksportować router. Czyli module.exports = router.
Dlaczego w ten sposób? Zaraz ci pokażę.
Przejdziemy sobie do index i będę chciał sobie to z kolei zainkludować. Napiszemy tutaj const api równa się
require("./api"), ale żeby plik api.js został wczytany, a nie nazywa się on index.js, to chcę ci przypomnieć, że
musimy w tym katalogu api utworzyć sobie plik package.json. A więc 32/api/package.json. I w nim podać klucz
main i tutaj napisać nazwę tego pliku, czyli api.js. W ten sposób powinno nam to działać i będziemy sobie mogli
po stronie tutaj pod api mieć to, co nam zwróci
exports w tym miejscu, czyli po prostu router. I teraz pokażę ci jeszcze jedną świetną rzecz, mianowicie
możemy tutaj po tej stronie wpisać sobie wyłącznie app.use(router). Zobaczysz, że nam to wszystko zadziała
dokładnie tak samo jak wcześniej.
Chociaż czekaj, pojawił nam się jakiś błąd. Tak, bo napisałem tutaj router, a chciałem napisać api. To zostało u
góry zwrócone.
Przejdźmy sobie tutaj. Działa.
I teraz jeżeli przejdziemy pod api/users, również działa. Więc za pomocą Postmana tak samo by nam działało.
Ale pokażę ci rzecz jeszcze lepszą.
Mianowicie nie chcę tutaj za każdym razem wpisywać /api, czyli sobie to pousuwamy.
Chcę po prostu wpisywać sobie tak jak to w tym API powinno działać, a tutaj po tej stronie możemy wpisać
app.use("/api) i przekazać ten router.
Mam nadzieję, że to jest jasne.
Czyli dopiero tutaj mówimy, że chcemy pod api korzystać z tego routera. W tym routerze tego nie ma.
I dokładnie w taki sam sposób będzie to działać, jeżeli wpiszę user np. 3, to również zostanie nam to
poprawnie zwrócone.
W ten sposób możesz sobie tworzyć zupełnie osobne routery, wstawiać je do osobnych plików i w tych miejscach
dopiero sobie definiować, w jaki sposób wszystko ma działać.
Na końcu taki router eksportujesz i możesz go w dowolnej swojej expressowej aplikacji zaimportować i
używać tylko dla danej ścieżki. Czyli tutaj sobie obsługujemy swoje ścieżki jakieś inne, ale potem możemy powiedzieć,
że dla /api obsłuż nam ten router, który tutaj został zwrócony. Choć ta lekcja była dosyć długa, to
mam nadzieję, że wytłumaczyłem ci, w jaki sposób tworzymy API typu REST.
Polegają one na tym, że wykonują cztery podstawowe operacje CRUD, czyli create, read, update oraz delete i
operują właśnie na takich URL-ach, jak pokazałem, czyli
ukośnik i nazwa jakby kolekcji wysłane pod get, czy wysłane jakby z typem get, ma nam zwrócić wszystkie takie
obiekty.
Jeżeli wyślemy pod ten sam adres post, to oczekujemy, że w tym post w body będą przekazane informacje,
które pozwolą nam utworzyć nowy obiekt.
Następnie get pod nazwa tego obiektu, ale jakby pojedyncza, czyli nie users, ale user, i ID pozwoli nam
zwrócić jeden taki obiekt. Dokładnie taki sam URL ale z metodą put pozwoli nam obiekt zaktualizować, ale
musimy te dane przesłać znowu jako body.
W tym przypadku również poprawnie jest sparsować.
Jeżeli wyślemy identyczne zapytanie, ale o metodzie HTTP delete, to wtedy będziemy chcieli usunąć taki
obiekt.
W tej lekcji nie posłużyliśmy się jednak bazą danych, ale takim prostym plikiem, który utworzyłem. Natomiast
w lekcji kolejnej będę chciał ci pokazać, jak możemy to API przerobić, by współpracowało z bazą danych
MongoDB.