Introduktion
Når du prøver at lære om nettet
udvikling, oplever vi normalt, at front-end er væsentligt mere tilgængelig end back-end. Der er mange grunde til dette, især følelsen af øjeblikkelig feedback, der kommer fra at ændre et bestemt element på en side i koden og bemærke, at ændringen bliver anvendt på webstedet. Denne feedback er ofte nyttig for begyndere, fordi den sætter dem i stand til at justere deres kode og lære af deres fejl. Desværre er det ikke tilfældet med backend: ofte er en betydelig mængde arbejde dedikeret til at opsætte miljøet på forhånd og installere de afhængigheder, der er nødvendige for at få en simpel "Hello World"-meddelelse til at blive vist på terminalen. Heldigvis, der sker konstant en masse fremskridt i open source-fællesskabet i retning af at lette udviklingsprocessen af frameworks, og forbedring af udviklerens oplevelse er et godt eksempel på dette kode i Javascript praktisk, og tilbyder en række indbyggede værktøjer og funktioner, der adskiller den fra sine konkurrenter. I denne artikel vil vi udforske NodeJs og dens økosystem, med en praktisk tilgang, og opbygge et fuldt funktionelt projekt.
Hvad skal vi bygge?
ToDo-applikationer er et go-to-projekt for begyndere, der lærer frontend-udvikling. Det er derfor, vi besluttede at bygge en Todo list API. Dette vil gøre os i stand til at tilføje datapersistens til vores grænseflade og give os mulighed for at manipulere disse data (ved at tilføje, opdatere, slette gøremål osv.).
Den endelige kode kan findes her.
Vores værktøjer
Vi vil bruge en forenklet teknologistack til dette projekt. Det kan betragtes som en minimal version af en masse værktøjer, du vil finde i virkelige projekter, grunden er, at ideerne på højere niveau er de samme. Detaljerne omkring implementering og valg af et specifikt værktøj frem for et andet er ikke vigtige for at komme i gang.
-
NodeJs, som vi nævnte, er en af de mest populære Javascript-frameworks til at bygge server-side applikationer.
-
ExpressJs er en minimal Javascript-ramme, der bruges oven på NodeJS. Det fremskynder udviklingsprocessen ved at bruge mange indbyggede funktioner. Det bruges også som en måde at standardisere udviklingspraksis i NodeJS-projekter for at lette brugen for ingeniører.
-
LowDB er en simpel database i hukommelsen. Dens enkelhed giver os mulighed for at vise, hvordan man interagerer med en database i et NodeJs-projekt uden at beskæftige sig med mere avancerede emner som implementeringer og konfigurationer.
Nu hvor vi har identificeret alle de værktøjer, vi vil bruge, lad os komme til vores tastaturer og begynde at kode!
Installation
Node er tilgængelig på alle platforme. Alle installationsvejledninger kan findes på den officielle hjemmeside. Windows-brugere bør sørge for at tilføje node sti til miljøvariabler, så den kan bruges på kommandolinjen.
Vi skal også have npm installeret. Npm er standardpakkehåndteringen for NodeJs. Det vil gøre os i stand til at styre vores projektafhængigheder. Installationsvejledningen kan findes her.
Projektinitialisering
Gå over til linket og klon startprojektet:
Dette er et simpelt startlager til vores projekt. Den indeholder alle de afhængigheder, vi vil bruge sammen med projektfilstrukturen. Vi vil forklare hvert element, når det er nået. Åbn din terminal, naviger til projektets sti og kør kommandoen:
npm install
Dette vil installere alle de afhængigheder af projektet, der er angivet i filen package.json. package.json er filen, der findes i roden af ethvert Javascript/NodeJs-projekt, den indeholder metadata om sidstnævnte og bruges til at administrere alle projektafhængigheder, scripts og versioner.
Når alle afhængigheder er installeret, kan vi starte vores applikation:
npm run start
"start" er et script, som vi har angivet i pakken. json filen. Det specificerer indtastningsfilen til vores applikation, som i vores tilfælde er app.js.
Følgende besked skulle nu vises i din terminal:
Det betyder, at vores server startede med succes og lytter efter eventuelle anmodninger sendt til port 3000. Lad os se på app.js og forklare, hvad der sker her:
App.js er vores projektindgangsfil (og den eneste på dette tidspunkt). Vi instansierer en ekspresapplikation ved navn app, specificerer, at alle anmodninger, der har http-metoden "GET" og understien '/', vil blive håndteret af denne rute, passerer i en funktion kaldet en middleware, som tager anmodningen og svarobjektet ind som parametre. Dette er afgørende, da forespørgslen indeholder al den information, der er nødvendig for, at den kan håndteres (parametre, forespørgselstekst, forespørgselsheadere osv..), og svarobjektet er det, der returneres til klienten. Vi starter med blot at sende "Hej verden" beskeden. Derefter får vi vores applikation til at lytte til alle indkommende anmodninger til den angivne port (i vores tilfælde 3000), og logger meddelelsen "Lytter til port 3000" for at indikere, at vores applikation er oppe og køre og klar til at modtage anmodninger.
Åbn din terminal og skriv "localhost:3000/" i linklinjen, og tryk på Enter. Dette er den angivne sti, som vi kan bruge til at nå vores server lokalt. Du vil modtage følgende besked:
Databasekonfiguration
Lowdb er en open source-database, der er nem at bruge og kræver ingen specifik opsætning. Den generelle idé bag det er at gemme alle data i en lokal json-fil. Efter LowDB er installeret (hvilket er blevet gjort, da vi installerede alle afhængigheder), kan vi tilføje følgende kode til db.js:
Denne kode er ret lig den, der findes på LowDBs officielle dokumentation. Vi har tilpasset det lidt til vores eget brug. Lad os forklare det linje for linje:
De første par linjer er til at importere de nødvendige afhængigheder. "Join" er en hjælpefunktion tilgængelig i "sti"-modulet. Det er et af kernemodulerne i NodeJs, der tilbyder en masse metoder til at håndtere og håndtere stier. "Low" og "JSONFile'' er de to klasser, der eksponeres af LowDB. Den første opretter json-filforekomsten, der vil indeholde vores data. Den anden opretter den faktiske databaseinstans, der vil handle på den. Endelig er "lodash" et af de mest brugte javascript-biblioteker, der tilbyder en bred vifte af hjælpefunktioner til almindelige programmeringsopgaver. Vi tilføjer det til vores databaseinstans for at gøre det muligt for os at bruge dets avancerede metoder til at håndtere vores data.
Først angiver vi stien til filen db.json. Det er filen, der vil indeholde vores data og blive videregivet til LowDB. Hvis filen ikke findes på den angivne sti, vil LowDB oprette en.
Vi sender derefter filstien til LowDB-adapteren og videregiver den til vores nye LowDB-databaseinstans. Variablen "db" kan derefter bruges til at kommunikere med vores database. Når databaseinstansen er oprettet, læser vi fra json-filen ved at bruge db.read(). Dette vil indstille "data"-feltet i vores databaseforekomst, så vi kan få adgang til databaseindholdet. Bemærk, at vi gik foran denne linje med "vent". Dette er for at specificere, at denne instruktion kan tage en ukendt tid at løse, og at NodeJs-processen skal vente på dens eksekvering, før den fortsætter med resten af koden. Vi gør dette, fordi læseoperationen kræver hukommelsesadgang til den angivne fil, og tiden til at udføre denne form for handling afhænger af dine maskinspecifikationer.
Nu hvor vi har adgang til datafeltet, indstiller vi det som et objekt, der indeholder en tom række af indlæg, eller rettere, vi tjekker, om filen indeholder tidligere data, og indstiller den tomme matrix, hvis det ikke er tilfældet.
Til sidst udfører vi db.write() for at anvende de ændringer, vi har lavet til dataene, og eksporterer databaseforekomsten, så den kan bruges i andre filer i vores projekt.
Arbejdsgang for generel anmodning/svar
Overvej følgende diagram:
Det viser den generelle arkitektur anvendt i et væld af backend-applikationer bygget med NodeJs/Express. At forstå den generelle arbejdsgang bag håndtering af en anmodning vil ikke kun give dig mulighed for at bygge og strukturere NodeJs applikationer, men også give dig mulighed for at overføre disse koncepter til praktisk talt enhver teknisk stak efter dit valg. Vi vil udforske de forskellige lag, der forstyrrer denne proces, og forklare deres roller:
## HTTP-anmodningslag
Dette er det første lag i vores applikation, forestil dig det som en gateway, der modtager en bred vifte af forskellige anmodninger, der kommer fra forskellige klienter, hver anmodning analyseres derefter og videresendes til den dedikerede del af applikationen, så den kan håndteres.
-
Routere: her henviser vi til Express-routere, men dette koncept kan findes i mange backend-frameworks. Routere er en måde at anvende den logiske fordeling i vores forretningslogik på vores kode, hvilket betyder, at hvert sæt af elementer, der deler lignende funktioner, håndteres af den samme post og kan adskilles fra resten af sættene. Dette har fordelen ved at gøre hver komponent i koden uafhængig af de andre og nemmere at vedligeholde og udvide. Mere specifikt, og som et eksempel, vil alle anmodninger, der opfylder betingelserne for den delte url-sti "/posts", blive håndteret af den samme router. Afhængigt af deres http-metode (GET, POST osv..), vil en anden controller blive brugt.
-
Controllere: en controller modtager filtrerede anmodninger fra routere, anvender yderligere behandling og kalder de passende servicemetoder.
Business Logic Layer
Dette lag er unikt afhængigt af applikationens specifikke anvendelsestilfælde og forretningslogikken bag den.
-
Tjenester: Tjenester er et sæt metoder, der indeholder applikationens kernelogik. De interagerer også med databasen ved hjælp af ORMs/ODMs.).
-
Tredjepartstjenester: Mange moderne applikationer vælger at uddelegere en del af applikationens logik til dedikerede tjenester, der er tilgængelige via en API. Tjenester af denne art kan være betalingshåndteringstjenester, lagring af statiske filer, meddelelser og andre.
-
ODM/ORM: ORM'er og ODM'er fungerer som mellemled mellem tjenesterne og databasen. Deres rolle er at levere en abstraktion på højt niveau på en database, der giver en udvikler mulighed for at skrive kode i det programmeringssprog, de selv vælger i stedet for dedikerede databasesprog, såsom SQL.
Data Persistence Layer
- Databaser: Som vi nævnte tidligere, har næsten alle applikationer brug for en form for datapersistens. Denne del håndteres af databaser, og afhængigt af arten af data, forretningslogikken og mange andre overvejelser, anses valget af en bestemt database frem for en anden for afgørende for applikationens effektivitet og skalerbarhed.
Eksempel: Tilføjelse af et indlæg
Nu hvor vi forstår den generelle idé bag arkitekturen, lad os anvende den på vores enkle eksempel. Vi implementerer funktionen med at tilføje et todo-indlæg til vores applikation. Lad os antage, at ethvert indlæg har et unikt id, der gør det muligt for os at identificere det senere i vores database, en titel, der er en streng, og en rækkefølge, der er af typen heltal. Efter vores diagram starter vi med at implementere routeren. Tilføj følgende kode til filen index.js:
Dette er vores routerfil. Vi importerer express og "addPost"-metoden fra vores controller (vi implementerer denne snart), opretter en instans af express-router og binder addPost-metoden til vores router - hvilket betyder, at for hver anmodning, der har rodstien og http metoden "POST", vil "addPost"-metoden blive kaldt til at håndtere den.
Før vi implementerer vores metode i controlleren, refererer vi til den nye router i vores app.js hovedfil og angiver dens sti som "/posts": Alle ruter med de angivne stier vil blive videresendt til denne router, så den kan håndteres ved de forskellige controller-metoder:
Vi importerer routeren og navngiver den som "indlæg". app.use(“/posts”,..) betyder, at alle anmodninger med understien “/posts”, uanset deres http-metode, vil blive dirigeret til den angivne router.
Andre ændringer af app.js omfatter import af databasekonfigurationsfilen, for at den kan blive eksekveret, og brug af express.json() som en middleware for at gøre det muligt for os at få adgang til anmodningens kropsobjekt.
Nu hvor vores ruter er indstillet, kan vi tilføje "addPost" metoden i controller.js filen:
"addPost" er en middleware-funktion, der tager anmodningen, svarobjekter og den næste funktion som parametre. Når den næste funktion kaldes, vil processen flytte til den næste middleware i kæden, eller afslutte anmodningen. I metodens kode udtrækker vi titlen og ordren fra anmodningsteksten og sender dem som parametre til servicefunktionen "createPost". Denne funktion tager post-attributterne, opretter et nyt indlæg og returnerer det. Når det nye indlæg er oprettet, returnerer vi det til klienten sammen med 200-statuskoden, hvilket betyder, at anmodningen er lykkedes. Du bemærker måske, at vores kode er sat inde i en try/catch-blok for at fange enhver uventet fejl og videregive den til den næste middleware. Det anses for at være bedste praksis at vedhæfte en fejlhåndteringsmiddleware til alle routere, der uddrager fejlen og returnerer en meningsfuld fejlmeddelelse til klienten.
Det eneste, der er tilbage nu, er at implementere "createPost"-funktionen i service.js:
Som vi nævnte tidligere, da vi forklarede de forskellige lag af arkitekturen, interagerer servicelaget med datalagringsløsningen ved brug af ORM/ODM. I vores eksempel behøver vi dog ikke bruge en separat ORM, da Lowdb kommer med indbygget understøttelse af Javascript. Alle detaljer om dens syntaks kan findes i dokumentationen.
"createPost"-metoden modtager titel og rækkefølge som parametre og bruger dem til at oprette post-objektet. Til det unikke id bruger vi et dedikeret bibliotek kaldet "nanoid", som genererer en unik sekvens af tegn. Vi tilføjer det nye indlæg til post-arrayet i databasen og skriver disse ændringer; det nye indlæg returneres derefter af funktionen.
Nu hvor "createPost" er klar, er tilføjelsesfunktionen nu færdig og kørende. Vi tester det ved hjælp af Postman, et populært værktøj til test af API'er:
Vi vælger "POST" som http-metoden for anmodningen sammen med den angivne url-sti "localhost:3000/posts". Vi tilføjer titlen og rækkefølgen som json-format i body-sektionen og sender anmodningen. Som vist ovenfor modtager vi statussen 200 OK sammen med det nyoprettede indlæg.
Konklusion
En masse koncepter og ideer er blevet undersøgt i dette projekt: Vi dækkede, hvordan man installerer og opsætter vores projektmiljø, lærte, hvordan man konfigurerer LowDB til lokal datapersistens, udforskede den generelle arkitektur af NodeJS/Express backend-applikationer og så, hvordan man anvende det i et simpelt eksempel. Til sidst testede vi vores applikation ved hjælp af Postman.
Hensigten her var at afsløre en forenklet version af alt, hvad der er med til at bygge moderne backend-applikationer. Som vi så tidligere, er NodeJs et kraftfuldt værktøj, der gør os i stand til at bygge enkle og komplekse API'er. Kombineret med dets rige økosystem af rammer, såsom ekspres og et væld af værktøjer og biblioteker til næsten enhver brugssituation, er det en legitim løsning til moderne backend-udvikling - en løsning, som vi anbefaler at lære og mestre.