Wstęp
Kiedy próbujesz dowiedzieć się o web
rozwoju, zwykle stwierdzamy, że front-end jest znacznie bardziej dostępny niż back-end. Powodów jest wiele, a szczególnie poczucie natychmiastowego feedbacku wynikającego ze zmiany jakiegoś elementu strony w kodzie i zauważenia, że zmiana została naniesiona na stronę. Ta informacja zwrotna jest często pomocna dla początkujących, ponieważ umożliwia im dostosowanie kodu i uczenie się na błędach. Niestety, w przypadku backendu tak nie jest: często znaczną ilość pracy poświęca się na wstępne skonfigurowanie środowiska i zainstalowanie zależności niezbędnych do uzyskania na terminalu prostego komunikatu „Hello World”. Na szczęście., w społeczności open source stale dokonuje się duży postęp w kierunku ułatwienia procesu tworzenia frameworków i poprawy doświadczenia programistów. NodeJs jest tego dobrym przykładem. Ten framework jest bardzo wydajną technologią, która umożliwia pisanie po stronie serwera kod w JavaScript jest wygodny i oferuje różnorodne wbudowane narzędzia i funkcje, które odróżniają go od konkurencji. W tym artykule przyjrzymy się NodeJs i jego ekosystemowi, stosując praktyczne podejście, tworząc w pełni funkcjonalny projekt.
Co zbudujemy?
Aplikacje ToDo to podstawowy projekt dla początkujących uczących się programowania front-end. Dlatego zdecydowaliśmy się zbudować API listy Todo. Umożliwi nam to dodanie trwałości danych do naszego interfejsu i umożliwi manipulowanie tymi danymi (poprzez dodawanie, aktualizowanie, usuwanie zadań itp.).
Ostateczny kod można znaleźć tutaj.
Nasze narzędzia
W tym projekcie użyjemy uproszczonego stosu technologicznego. Można go uznać za minimalną wersję wielu narzędzi, które można znaleźć w rzeczywistych projektach, ponieważ pomysły wyższego poziomu są takie same. Szczegóły wdrożenia i wybór konkretnego narzędzia zamiast drugiego nie są istotne na początek.
-
NodeJs, jak już wspomnieliśmy, jest jednym z najpopularniejszych frameworków Javascript do budowy aplikacji serwerowych.
-
ExpressJs to minimalny framework JavaScript używany na NodeJS. Przyspiesza proces rozwoju dzięki wykorzystaniu wielu wbudowanych funkcji. Jest również stosowany jako sposób na standaryzację praktyk programistycznych w projektach NodeJS, aby ułatwić inżynierom korzystanie z niego.
-
LowDB to prosta baza danych przechowywana w pamięci. Jego prostota pozwala nam pokazać, jak współdziałać z bazą danych w projekcie NodeJs, bez zajmowania się bardziej zaawansowanymi tematami, takimi jak wdrożenia i konfiguracje.
Teraz, gdy zidentyfikowaliśmy wszystkie narzędzia, których będziemy używać, przejdźmy do naszych klawiatur i zacznijmy kodować!
Instalacja
Węzeł jest dostępny na wszystkich platformach. Wszystkie instrukcje instalacji można znaleźć na oficjalnej stronie internetowej. Użytkownicy systemu Windows powinni pamiętać o dodaniu węzła ścieżka do zmiennych środowiskowych, aby można było go używać w wierszu poleceń.
Będziemy również potrzebować zainstalowanego npm. Npm to standardowy menedżer pakietów dla NodeJs. Umożliwi nam to zarządzanie zależnościami naszych projektów. Instrukcję instalacji można znaleźć tutaj.
Inicjalizacja projektu
Przejdź do linku i sklonuj projekt startowy:
Jest to proste repozytorium startowe dla naszego projektu. Zawiera wszystkie zależności, z których będziemy korzystać wraz ze strukturą pliku projektu. Po osiągnięciu każdego elementu wyjaśnimy. Otwórz terminal, przejdź do ścieżki projektu i uruchom polecenie:
npm install
Spowoduje to zainstalowanie wszystkich zależności projektu określonych w pliku package.json. package.json to plik znajdujący się w katalogu głównym dowolnego projektu Javascript/NodeJs. Zawiera metadane dotyczące tego ostatniego i służy do zarządzania wszystkimi zależnościami projektu, skryptami i wersjami.
Po zainstalowaniu wszystkich zależności możemy uruchomić naszą aplikację:
npm run start
„start” to skrypt określony w pakiecie. plik json. Określa plik wejściowy naszej aplikacji, którym w naszym przypadku jest app.js.
Następujący komunikat powinien teraz pojawić się w Twoim terminalu:
Oznacza to, że nasz serwer wystartował pomyślnie i nasłuchuje żądań wysłanych na port 3000. Przyjrzyjmy się plikowi app.js i wyjaśnijmy, co się tutaj dzieje:
App.js to plik wejściowy naszego projektu (i jedyny w tym momencie). Tworzymy instancję aplikacji ekspresowej o nazwie app, określamy, że wszystkie żądania posiadające metodę http „GET” i ścieżkę podrzędną „/” będą obsługiwane przez tę trasę, przekazujemy funkcję zwaną oprogramowaniem pośredniczącym, która przyjmuje obiekt żądania i odpowiedzi jako parametry. Jest to o tyle istotne, że żądanie zawiera wszystkie informacje potrzebne do jego obsługi (parametry, treść żądania, nagłówki żądania itp.), a obiekt odpowiedzi to ten, który zostanie zwrócony klientowi. Zaczynamy od wysłania wiadomości „Witaj, świecie”. Następnie sprawiamy, że nasza aplikacja nasłuchuje wszelkich żądań przychodzących do określonego portu (w naszym przypadku 3000) i rejestrujemy komunikat „Nasłuchiwanie portu 3000”, aby wskazać, że nasza aplikacja jest uruchomiona i gotowa do odbierania żądań.
Otwórz terminal i na pasku łączy wpisz „localhost:3000/” i naciśnij Enter. Jest to określona ścieżka, za pomocą której możemy dotrzeć lokalnie do naszego serwera. Otrzymasz następujący komunikat:
Konfiguracja bazy danych
Lowdb to baza danych typu open source, która jest łatwa w użyciu i nie wymaga szczególnej konfiguracji. Ogólną ideą jest przechowywanie wszystkich danych w lokalnym pliku json. Po zainstalowaniu LowDB (co zostało zrobione, gdy zainstalowaliśmy wszystkie zależności), możemy dodać następujący kod do db.js:
Ten kod jest dość podobny do tego, który można znaleźć w oficjalnej dokumentacji LowDB. Zmodyfikowaliśmy go trochę na potrzeby naszego własnego zastosowania. Wyjaśnijmy to linijka po linijce:
Pierwsze kilka wierszy służy do importowania niezbędnych zależności. „join” to funkcja narzędziowa dostępna w module „ścieżka”. Jest to jeden z podstawowych modułów NodeJs, który oferuje wiele metod obsługi ścieżek. „Low” i „JSONFile” to dwie klasy udostępniane przez LowDB. Pierwsza tworzy instancję pliku json, która będzie zawierać nasze dane. Drugi tworzy rzeczywistą instancję bazy danych, która będzie na niej działać. Wreszcie, „lodash” jest jedną z najczęściej używanych bibliotek JavaScript, oferującą szeroką gamę funkcji narzędziowych do typowych zadań programistycznych. Dodajemy go do naszej instancji bazy danych, abyśmy mogli korzystać z jej zaawansowanych metod obsługi naszych danych.
Najpierw określamy ścieżkę do pliku db.json. Jest to plik, który będzie zawierał nasze dane i zostanie przekazany do LowDB. Jeżeli plik nie zostanie znaleziony w podanej ścieżce, LowDB go utworzy.
Następnie przekazujemy ścieżkę pliku do adaptera LowDB i przekazujemy ją do naszej nowej instancji bazy danych LowDB. Zmienną „db” można następnie wykorzystać do komunikacji z naszą bazą danych. Po utworzeniu instancji bazy danych odczytujemy z pliku json za pomocą db.read(). Spowoduje to ustawienie pola „dane” w naszej instancji bazy danych, dzięki czemu będziemy mogli uzyskać dostęp do zawartości bazy danych. Zauważ, że poprzedziliśmy tę linię słowem „czekaj”. Ma to na celu określenie, że rozwiązanie tej instrukcji może zająć nieznaną ilość czasu i że proces NodeJs musi poczekać na wykonanie, zanim będzie mógł kontynuować resztę kodu. Robimy to, ponieważ operacja odczytu wymaga dostępu do pamięci określonego pliku, a czas wykonania tego rodzaju operacji zależy od specyfikacji komputera.
Teraz, gdy mamy już dostęp do pola danych, ustawiamy je jako obiekt zawierający pustą tablicę postów, a raczej sprawdzamy, czy plik zawiera jakieś wcześniejsze dane i ustawiamy pustą tablicę, jeśli tak nie jest.
Na koniec wykonujemy db.write(), aby zastosować modyfikacje, które wprowadziliśmy do danych i wyeksportować instancję bazy danych, aby można ją było wykorzystać w innych plikach naszego projektu.
Ogólny przepływ pracy dotyczący żądania/odpowiedzi
Rozważ następujący diagram:
Pokazuje ogólną architekturę stosowaną w wielu aplikacjach backendowych zbudowanych przy użyciu NodeJs/Express. Zrozumienie ogólnego przepływu pracy związanego z obsługą żądania nie tylko pozwoli Ci budować i strukturyzować aplikacje NodeJs, ale także umożliwi przeniesienie tych koncepcji do praktycznie dowolnego wybranego stosu technicznego. Zbadamy różne warstwy zakłócające ten proces i wyjaśnimy ich rolę:
## Warstwa żądań HTTP
To pierwsza warstwa naszej aplikacji, wyobraźcie sobie ją jako bramę, która odbiera szeroką gamę różnych żądań pochodzących od różnych klientów, każde żądanie jest następnie analizowane i przekazywane do dedykowanej części aplikacji w celu jego obsługi.
-
Routery: tutaj mamy na myśli routery Express, ale tę koncepcję można znaleźć w wielu frameworkach backendowych. Routery umożliwiają zastosowanie rozkładu logicznego w naszej logice biznesowej do naszego kodu, co oznacza, że każdy zestaw elementów o podobnych funkcjach jest obsługiwany przez ten sam wpis i można go oddzielić od pozostałych zestawów. Ma to tę zaletę, że każdy komponent kodu jest niezależny od pozostałych oraz łatwiejszy w utrzymaniu i rozszerzaniu. Mówiąc dokładniej, jako przykład, wszystkie żądania spełniające warunki udostępnionej ścieżki adresu URL „/posts” będą obsługiwane przez ten sam router. W zależności od metody http (GET, POST itp.) zostanie użyty inny kontroler.
-
Kontrolery: kontroler odbiera filtrowane żądania z routerów, stosuje dodatkowe przetwarzanie i wywołuje odpowiednie metody usług.
Warstwa logiki biznesowej
Ta warstwa jest unikalna w zależności od konkretnych przypadków użycia aplikacji i logiki biznesowej, która się za nią kryje.
-
Usługi: Usługi to zestaw metod zawierających podstawową logikę aplikacji. Wchodzą w interakcję z bazą danych za pomocą ORM/ODM.
-
Usługi stron trzecich: wiele nowoczesnych aplikacji decyduje się na delegowanie części logiki aplikacji do dedykowanych usług dostępnych poprzez API. Usługami tego typu mogą być obsługa płatności, przechowywanie plików statycznych, powiadomienia i inne.
-
ODM/ORM: ORM i ODM pełnią rolę pośredników pomiędzy usługami a bazą danych. Ich rolą jest zapewnienie abstrakcji wysokiego poziomu bazy danych, która umożliwia programistom pisanie kodu w wybranym przez siebie języku programowania zamiast w dedykowanych językach baz danych, takich jak SQL.
Warstwa trwałości danych
- Bazy danych: jak wspomnieliśmy wcześniej, prawie wszystkie aplikacje wymagają jakiejś formy trwałości danych. Ta część jest obsługiwana przez bazy danych i w zależności od charakteru danych, logiki biznesowej i wielu innych czynników, wybór konkretnej bazy danych zamiast innej jest uważany za kluczowy dla wydajności i skalowalności aplikacji.
Przykład: dodanie wpisu
Teraz, gdy rozumiemy ogólną ideę architektury, zastosujmy ją do naszego prostego przykładu. Wdrożymy możliwość dodania posta todo do naszej aplikacji. Załóżmy, że każdy post ma unikalny identyfikator, który pozwoli nam go później zidentyfikować w naszej bazie, tytuł będący ciągiem znaków oraz kolejność typu integer. Kierując się naszym diagramem, zaczniemy od wdrożenia routera. Dodaj następujący kod do pliku Index.js:
To jest nasz plik routera. Importujemy express i metodę „addPost” z naszego kontrolera (wkrótce ją zaimplementujemy), tworzymy instancję routera express i wiążemy metodę addPost z naszym routerem - co oznacza, że dla każdego żądania, które ma ścieżkę root i http metodą „POST”, do jej obsługi zostanie wywołana metoda „addPost”.
Zanim zaimplementujemy naszą metodę w kontrolerze, odwołujemy się do nowego routera w naszym głównym pliku app.js i określamy jego ścieżkę jako „/posts”: Wszystkie trasy z określonymi ścieżkami zostaną przekazane do tego routera, aby mógł być obsługiwany różnymi metodami kontrolera:
Importujemy router i nazywamy go „posts”. app.use(„/posts”,..) oznacza, że wszystkie żądania ze ścieżką podrzędną „/posts”, niezależnie od metody http, będą kierowane do określonego routera.
Inne zmiany w app.js obejmują import pliku konfiguracyjnego bazy danych w celu jego wykonania oraz użycie express.json() jako oprogramowania pośredniczącego, które umożliwia nam dostęp do obiektu treści żądania.
Teraz, gdy nasze trasy są już ustawione, możemy dodać metodę „addPost” w pliku kontroler.js:
„addPost” to funkcja oprogramowania pośredniego, która przyjmuje jako parametry żądanie, obiekty odpowiedzi i następną funkcję. Po wywołaniu następnej funkcji proces zostanie przeniesiony do następnego oprogramowania pośredniczącego w łańcuchu lub zakończy żądanie. W kodzie metody wyodrębniamy tytuł i kolejność z treści żądania i przekazujemy je jako parametry do funkcji serwisowej „createPost”. Ta funkcja pobiera atrybuty postu, tworzy nowy post i zwraca go. Po utworzeniu nowego wpisu zwracamy go do klienta wraz z kodem statusu 200, co oznacza, że żądanie zostało zrealizowane. Możesz zauważyć, że nasz kod jest umieszczony w bloku try/catch w celu wyłapania nieoczekiwanego błędu i przekazania go do następnego oprogramowania pośredniczącego. Za najlepszą praktykę uważa się dołączenie do wszystkich routerów oprogramowania pośredniego obsługującego błędy, które wyodrębnia błąd i zwraca klientowi znaczący komunikat o błędzie.
Pozostało już tylko zaimplementować funkcję „createPost” w service.js:
Jak wspomnieliśmy wcześniej, wyjaśniając różne warstwy architektury, warstwa usług współdziała z rozwiązaniem do przechowywania danych poprzez wykorzystanie ORM/ODM. Jednak w naszym przykładzie nie będziemy musieli używać osobnego ORM-a, ponieważ Lowdb ma wbudowaną obsługę JavaScript. Wszystkie szczegóły dotyczące jego składni można znaleźć w dokumentacji.
Metoda „createPost” otrzymuje tytuł i kolejność jako parametry i wykorzystuje je do utworzenia obiektu postu. Do unikalnego identyfikatora wykorzystujemy dedykowaną bibliotekę o nazwie „nanoid”, która generuje unikalny ciąg znaków. Dodajemy nowy post do tablicy postów w bazie danych i zapisujemy te zmiany; funkcja zwraca następnie nowy post.
Teraz, gdy „createPost” jest gotowy, funkcja dodawania postów jest już ukończona i działa. Testujemy to za pomocą Postmana, popularnego narzędzia do testowania API:
Wybieramy „POST” jako metodę http dla żądania wraz z określoną ścieżką adresu URL „localhost:3000/posts”. Dodajemy tytuł i kolejność w formacie json w sekcji treści i wysyłamy żądanie. Jak widać powyżej, wraz z nowo utworzonym postem otrzymujemy status 200 OK.
Wniosek
W tym projekcie zbadano wiele koncepcji i pomysłów: omówiliśmy, jak zainstalować i skonfigurować nasze środowisko projektowe, nauczyliśmy się konfigurować LowDB pod kątem trwałości danych lokalnych, zbadaliśmy ogólną architekturę aplikacji backendowych NodeJS/Express i zobaczyliśmy, jak zastosuj to na prostym przykładzie. Na koniec przetestowaliśmy naszą aplikację za pomocą Postmana.
Zamiarem było pokazanie uproszczonej wersji wszystkiego, co wiąże się z tworzeniem nowoczesnych aplikacji backendowych. Jak widzieliśmy wcześniej, NodeJs to potężne narzędzie, które pozwala nam budować proste i złożone interfejsy API. W połączeniu z bogatym ekosystemem frameworków, takich jak express oraz mnóstwem narzędzi i bibliotek do niemal każdego przypadku użycia, jest to legalne rozwiązanie do tworzenia nowoczesnego backendu - rozwiązanie, którego zalecamy się nauczyć i opanować.