de Ayo Isaiah

Aflați Node.js prin crearea unei aplicații Timestamp Microservice

Fotografie de Devon Janse van Rensburg pe Unsplash

Unul dintre motivele pentru care Node.js este o platformă atât de bună pentru crearea de aplicații este abundența bibliotecilor dezvoltate de comunitate pentru practic toate cazurile de utilizare obișnuite. Acest lucru face cu ușurință trecerea de la idee la o aplicație pregătită pentru producție într-un spațiu de timp relativ scurt.

Acestea fiind spuse, cel puțin înțelegerea bibliotecilor standard ale Node.js va fi întotdeauna benefică pentru dvs., mai ales dacă doriți să înțelegeți mai bine cum funcționează Node.js.

În acest articol, veți învăța cum să construiți un microserviciu timestamp folosind câteva module Node.js încorporate. Iată un demo live despre ceea ce vom construi. Puteți găsi codul sursă complet pentru acest proiect în acest document Repo GitHub.

Condiții prealabile

Trebuie să aveți experiență anterioară cu crearea de aplicații JavaScript în browser, dar nu este necesară nicio experiență prealabilă cu Node.js. Totuși, înainte de a continua, trebuie să aveți Node.js și npm instalat.

Puteți vizita Site-ul web Node.js pentru a vizualiza instrucțiunile de instalare pentru sistemul dvs. de operare. npm vine la pachet cu Node, deci odată ce instalați Node, veți avea acces la npm comandă și el.

Versiunile pe care le-am folosit la construirea acestui proiect sunt următoarele:

  • Node.js v10.9.0
  • npm v6.4.1

Puteți vizualiza versiunea Node și npm ați instalat executând următoarele comenzi în terminal:

node -vnpm -v

Poveștile utilizatorilor

Iată poveștile utilizatorilor pentru acest proiect:

  1. Punctul final API este GET [project_url]/api/timestamp/:date_string?
  2. Un șir de date este valid dacă poate fi analizat cu succes de new Date(date_string). Rețineți că marcajul de timp Unix trebuie să fie un număr întreg (nu un șir) care să specifice milisecunde. În testul nostru vom folosi șiruri de date conforme ISO-8601 (de exemplu, „2016-11-20”), deoarece acest lucru va asigura o marcă de timp UTC.
  3. Dacă șirul de date este gol, ar trebui să fie echivalent cu declanșatorul new Date(), adică serviciul folosește ora actuală.
  4. Dacă șirul de date este valid, API returnează un JSON având structura {"unix": <date.getTime()>, "utc" : <date.toUTCStinel()> } e.g. {"unix": 1479663089000 ,"utc": "Sun, 20 Nov 2016 17: 31: 29 GMT “}.
  5. Dacă șirul de date nu este valid, API returnează un JSON având structura {"error" : "Invalid Date" }.

Noțiuni de bază

Deschideți o nouă instanță de terminal pe computer, apoi creați un director nou pentru acest proiect în sistemul de fișiere și schimbați-l folosind următoarele comenzi:

mkdir timestamp-microservicecd timestamp-microservice

Primul pas când începeți un nou proiect Node este inițializarea acestuia cu un package.json fişier. Acest fișier conține câteva informații despre un proiect, inclusiv numele, descrierea, autorul și toate pachetele de care depinde. Iată comanda care vă ajută să creați un package.json fișier pentru proiectul dvs.:

npm init

Rularea comenzii de mai sus deschide un prompt care vă permite să introduceți informațiile pentru anumite părți ale proiectului dvs. în următoarea ordine:

  1. Numele proiectului.
  2. Versiunea inițială a proiectului.
  3. Descrierea proiectului.
  4. Fișierul de intrare al proiectului.
  5. Comanda de testare a proiectului.
  6. Depozitul git pentru proiect,
  7. Cuvinte cheie legate de proiect.
  8. Licența proiectului.

Dacă sunteți mulțumit de sugestia pe care comanda o oferă lângă fiecare câmp (între paranteze), apăsați tasta Enter pentru ao accepta și treceți la câmpul următor până când comanda iese. Puteți utiliza, de asemenea npm init -y a popula rapid un package.json fișier cu toate valorile implicite.

Următorul pas este crearea unui index.js fișierul din rădăcina directorului de proiect. Aici vom scrie codul pentru acest proiect.

touch index.js

În cele din urmă, creați un views folder din rădăcina directorului de proiect. Acest dosar va conține două fișiere HTML: index.html și 404.html.

mkdir viewstouch views/index.html views/404.html

Deschideți folderul proiectului în editorul de text preferat. Acum putem începe să construim aplicația.

Aflati Nodejs construind o aplicatie Timestamp Microservice

Creați un server web HTTP

Deschide index.js și introduceți următorul cod în el:

const http = require("http");
const requestHandler = (req, res) => {  console.log(req.url);  res.end('Hello world!');};
const server = http.createServer(requestHandler);
server.listen(process.env.PORT || 4100, err => {  if (err) throw err;
console.log(`Server running on PORT ${server.address().port}`);});

Prima linie necesită http modul care se livrează cu Node și îl face accesibil prin intermediul http variabil. Apoi, folosim createServer metoda de pe modulul http pentru a crea o nouă instanță a unui server HTTP care este apoi stocat în server variabil.

Observați requestHandler funcție creată sub http variabil. Această funcție va fi invocată la fiecare solicitare primită către serverul web. req și res argumentele sunt obiecte care reprezintă cererea de la răspunsul clientului și respectiv al serverului.

listen metoda pornește serverul și îl face să asculte conexiunile primite pe PORT variabila de mediu (disponibilă pe process.env obiect) sau 4100 dacă nu e nimic acolo. Funcția de apel invers a trecut la listen metoda se va executa la pornirea serverului. Dacă portul furnizat este deja preluat sau serverul nu poate porni din orice alt motiv, se aruncă o eroare. În caz contrar, console.log() declarația este tipărită în terminal.

Puteți porni serverul rulând node index.js în terminal. Odată ce serverul dvs. rulează, vizitați http: // localhost: 4100 în browserul dvs. Ar trebui să vedeți cuvintele „Hello world!”.

1612152072 870 Aflati Nodejs construind o aplicatie Timestamp Microservice

Creați ruta rădăcină

Din moment ce http modulul este foarte de bază, nu ne oferă un router. Deci, trebuie să verificăm manual adresa URL pentru a decide ce să facem pentru fiecare rută. Vrem să oferim instrucțiuni despre cum să utilizați microserviciul de marcare de timp odată ce ruta rădăcină este lovită la fel ca în demonstrație.

Putem face acest lucru modificând fișierul requestHandler funcționează astfel:

const requestHandler = (req, res) => {  if (req.url === "https://www.freecodecamp.org/") {    // Do something  }};

Un simplu if declarația ne poate ajuta să verificăm dacă adresa URL a solicitării primite este exactă / și apoi putem pune logica acelei rute între acolade. În acest caz, dorim să returnăm un cod HTML care să explice cum funcționează microserviciul. Înainte de a continua, copiați și lipiți următoarele în views/index.html fișier pe care l-am creat anterior și salvăm fișierul.

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <title>Timestamp Microservice</title>  <style>    body {      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;      color: #333;        background-color: #f6f6f6;    }
.container {      width: 100%;      max-width: 800px;      margin-left: auto;      margin-right: auto;    }
li {      margin-bottom: 10px;    }
li, p {      font-size: 18px;    }
code {      font-size: 90%;    }
a {      color: #006fc6;    }  </style></head><body>  <div class="container">    <h1>API Project: Timestamp Microservice</h1>    <h3>User Stories:</h1>    <ol class="user-stories">      <li>The API endpoint is <code>GET [project_url]/api/timestamp/:date_string</code></li>      <li>A date string is valid if can be successfully parsed by <code>new Date(date_string)</code>.<br>        Note that the unix timestamp needs to be an <strong>integer</strong> (not a string) specifying <strong>milliseconds</strong>.<br>        In our test we will use date strings compliant with ISO-8601 (e.g. <code>"2016-11-20"</code>) because this will ensure an UTC timestamp.</li>      <li>If the date string is <strong>empty</strong> it should be equivalent to trigger <code>new Date()</code>, i.e. the service uses the current timestamp.</li>      <li>If the date string is <strong>valid</strong> the api returns a JSON having the structure<br><code>{"unix": <date.getTime()>, "utc" : <date.toUTCString()> }</code><br>        e.g. <code>{"unix": 1479663089000 ,"utc": "Sun, 20 Nov 2016 17:31:29 GMT"}</code></li>      <li>If the date string is <strong>invalid</strong> the api returns a JSON having the structure <br>        <code>{"error" : "Invalid Date" }</code>.      </li>    </ol>
<h3>Example Usage:</h3>    <ul>      <li>        <a href="https://www.freecodecamp.org/news/microservice-8edfdb9be811/api/timestamp/2015-12-25">[project url]/api/timestamp/2015-12-25</a>      </li>      <li>        <a href="api/timestamp/1450137600000">[project url]/api/timestamp/1450137600</a>      </li>    </ul>
<h3>Example Output:</h3>    <p>      <code>{"unix":1451001600000, "utc":"Fri, 25 Dec 2015 00:00:00 GMT"}</code>    </p>  </div></body></html>

Deci, cum trimitem un răspuns HTML browserului? Putem folosi dispozitivul încorporat fs pentru a citi fișierul și apoi trimite conținutul fișierului la browser folosind res argument care reprezintă răspunsul serverului.

Solicitați fs modul aflat chiar sub http una așa cum se arată mai jos:

const http = require("http");const fs = require("fs");

Apoi modificați fișierul requestHandler funcția de a arăta astfel:

const requestHandler = (req, res) => {  if (req.url === "https://www.freecodecamp.org/") {    fs.readFile("views/index.html", "utf8", (err, html) => {      if (err) throw err;
res.writeHead(200, { "Content-Type": "text/html" });      res.end(html);    });  }};

readFile() metoda citește în mod asincron fișierul furnizat în primul argument (views/index.html) folosind codificarea furnizată (utf8) și execută funcția de apelare furnizată. Dacă apare o eroare la citirea fișierului, se lansează o excepție. În caz contrar, conținutul fișierului devine disponibil în al doilea argument al funcției callback (html) în acest caz.

Acum, putem trimite conținutul fișierului html la browser. Dar trebuie să setăm Cod de răspuns HTTP precum și setați un antet de răspuns pentru a spune browserului care este tipul media al conținutului returnat.

writeHead() metoda de pe obiectul de răspuns al serverului este utilizată în acest caz. Acceptă codul de stare ca primul argument și un obiect care reprezintă antetele de răspuns ca al doilea. Am stabilit Content-Type antet la text/html pentru a se asigura că browserul interpretează conținutul răspunsului nostru ca HTML.

Apoi, end() metoda trimite conținutul fișierului index.html fișierul către browserul din corpul răspunsului și semnalează sfârșitul răspunsului serverului.

Pentru a încerca noile adăugiri la cod, trebuie să opriți serverul cu Ctrl-C și să îl reporniți folosind node server.js, apoi reîmprospătați browserul. Ar trebui să vedeți html din views/index.html fișier pe pagină.

Configurați Nodemon pentru a reporni automat procesul Node

În mod implicit, trebuie să omoriți procesul serverului și să-l reporniți de fiecare dată când modificați codul, dar există o modalitate ușoară de a evita acest lucru.

Trebuie să instalați un instrument numit Nodemon care repornește automat procesul de nod ori de câte ori codul dvs. se modifică. Puteți instala acest instrument la nivel global pe mașina dvs. cu npm:

npm install -g nodemon

Odată instalat Nodemon, ucideți procesul serverului și porniți-l din nou cu nodemon index.js. Acum, serverul web va fi repornit automat ori de câte ori modificați codul. Destul de îngrijit nu?

Următorul pas este să configurați o rută pentru microserviciul de marcare de timp. În conformitate cu povestea utilizatorului # 1, acest serviciu ar trebui să fie disponibil sub /api/timestamp/:date_string? Unde :date_string? reprezintă șirul de date care va fi transmis serviciului.

Modificați-vă index.js fișier, astfel încât să arate astfel:

// require statements
const getTimestamp = date => ({  unix: date.getTime(),  utc: date.toUTCString()});
const requestHandler = (req, res) => {  if (req.url === "https://www.freecodecamp.org/") {    fs.readFile("views/index.html", (err, html) => {      if (err) throw err;
res.writeHead(200, { "Content-Type": "text/html" });      res.end(html);    });  } else if (req.url.startsWith("/api/timestamp")) {    const dateString = req.url.split("/api/timestamp/")[1];    let timestamp;
if (dateString === undefined || dateString.trim() === "") {      timestamp = getTimestamp(new Date());    } else {      const date = !isNaN(dateString)        ? new Date(parseInt(dateString))        : new Date(dateString);
if (!isNaN(date.getTime())) {        timestamp = getTimestamp(date);      } else {        timestamp = {          error: "invalid date"        };      }    }
res.writeHead(200, { "Content-Type": "application/json" });    res.end(JSON.stringify(timestamp));  }};
// rest of the file

Știu că este o mulțime de coduri de procesat, așa că permiteți-mi să vă trec puțin câte puțin prin el. Avem un else if declarație în requestHandler care verifică dacă adresa URL a cererii începe cu /api/timstamp. Dacă da, noi split adresa URL a cererii în două și apucați dateString desparte matricea rezultată.

Dacă dateString este undefined sau un șir gol, înseamnă că nu a fost furnizat niciun șir de date în cerere. Povestea utilizatorului nr. 3 dictează că tratăm situația ca și cum data actuală ar fi solicitată și asta este ceea ce getTimestamp(new Date()) face.

În cazul în care un dateString există, trebuie să verificăm dacă este un timestamp unix sau un șir de date ISO-8601 (cum ar fi „2018-11-22”), astfel încât să putem decide dacă trecem un număr sau un șir către new Date(). Rețineți că, dacă treceți un timestamp unix ca șir către new Date(), veți obține un rezultat nevalid. De aceea este necesar acest pas.

Apoi, verificăm dacă obiectul de dată stocat în date variabila este valabilă. Dacă da, obținem obiectul timestamp ca înainte, altfel setăm timestamp variabilă la structura pentru date nevalide, așa cum se specifică în povestea utilizatorului # 5.

Pasul final este de a trimite conținutul fișierului timestamp variabilă pentru browser. În acest caz, setăm Content-Type antet la application/json astfel încât corpul de răspuns să fie interpretat corect ca JSON. De asemenea, ne asigurăm că trimitem o valoare JSON validă apelând JSON.stringify(timestamp) și trecerea ieșirii la end metodă.

Acum, testați aplicația trecând un șir de date valid sau un timestamp unix după /api/timestamp/ sau lăsați șirul de date afară pentru a obține un răspuns JSON pentru data curentă. De asemenea, puteți încerca să treceți un șir de date nevalide pentru a confirma că serviciul îl recunoaște ca o dată nevalidă.

Implementați o pagină 404

Am completat toate poveștile utilizatorilor pentru această aplicație, dar aș vrea să facem un ultim lucru. Dacă browserul solicită o adresă URL care nu este / sau începe cu /api/timestamp, ar trebui să configurăm serverul pentru a trimite un răspuns 404 browserului.

În primul rând, populează views/404.html fișier cu următorul cod:

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <title>404 Not found</title></head><body>  <h1>undefined is, unfortunately, not a function</h1>  <p>You just 404'd. Maybe you should head back to the <a href="https://www.freecodecamp.org/">homepage</a>.</p><script></script></body></html>

Apoi, modificați fișierul requestHandler funcționează în index.js astfel încât să arate astfel:

const requestHandler = (req, res) => {  if (req.url === "https://www.freecodecamp.org/") {    fs.readFile("views/index.html", (err, html) => {      if (err) throw err;
res.writeHead(200, { "Content-Type": "text/html" });      res.end(html);    });  } else if (req.url.startsWith("/api/timestamp")) {    const dateString = req.url.split("/api/timestamp/")[1];    let timestamp;
if (dateString === undefined || dateString.trim() === "") {      timestamp = getTimestamp(new Date());    } else {      const date = !isNaN(dateString)        ? new Date(parseInt(dateString))        : new Date(dateString);
if (!isNaN(date.getTime())) {        timestamp = getTimestamp(date);      } else {        timestamp = {          error: "invalid date"        };      }    }
res.writeHead(200, { "Content-Type": "application/json" });    res.end(JSON.stringify(timestamp));  } else {    fs.readFile("views/404.html", (err, html) => {      if (err) throw err;
res.writeHead(404, { "Content-Type": "text/html" });      res.end(html);    });  }};

Am adăugat o finală else bloc la sfârșitul requestHandler funcție care citește conținutul fișierului views/404.html fișierul și îl trimite către browser pentru orice adresă URL care nu se potrivește / sau /api/timestamp/:date_string?.

Încearcă. Introduceți o adresă URL de genul http: // localhost: 4100 / foo în browserul dvs. și confirmați că funcționează!

1612152072 556 Aflati Nodejs construind o aplicatie Timestamp Microservice

Distribuiți pe Heroku

La ce bun un microserviciu cu marcaj de timp dacă nimeni nu îl poate folosi? Să-l împărtășim lumii implementându-l în Heroku.

Primul pas este să creați un cont Heroku gratuit. Odată ce contul dvs. este activat, urmați acest link pentru a crea o aplicație nouă. Dă-i un nume unic. Am numit-o pe „ayo-timestamp”.

Odată ce aplicația dvs. este creată, urmați instrucțiunile de aici pentru a instala Heroku CLI pe mașină. Apoi rulați heroku login comanda din terminal pentru a vă conecta la contul dvs. Heroku.

Asigurați-vă că ați inițializat un depozit git pentru proiectul dvs. Dacă nu, rulați git init comanda din rădăcina directorului de proiect, apoi executați comanda de mai jos pentru a seta heroku ca telecomandă pentru repozitia dvs. git. A inlocui <app naeu> cu numele aplicației dvs.

heroku git:remote -a <app name>

Apoi, creați un Procfile în rădăcina directorului de proiect (touch Procfile) și lipiți în următorul conținut:

web: node index.js

Apoi, specificați versiunea de nod pe care o executați în package.json fișier sub engines cheie. Am specificat versiunea 10.9.0 deoarece aceasta este versiunea pe care o rulez pe computerul meu. Ar trebui să modificați acea valoare pentru a se potrivi cu versiunea de nod pe care o aveți pe computer.

{  "name": "timestamp-microservice",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "test": "echo "Error: no test specified" && exit 1"  },  "keywords": [],  "author": "Ayo Isaiah",  "license": "MIT",  "engines": {    "node": "10.9.0"  }}

În cele din urmă, comiteți codul și împingeți-l la telecomanda Heroku folosind următoarele comenzi:

git add .git commit -m "Initial commit"git push heroku master

Odată ce procesul de implementare este finalizat, puteți deschide https://<your-app-name>.heroku.com pentru a vizualiza și testa proiectul.

Învelire

Am creat cu succes un microserviciu cu marcaj de timp folosind doar module Node încorporate și l-am implementat în Heroku. Pentru a fi sigur, folosind cadre web cum ar fi Expres este mai ușor și mai practic pentru aplicații non-banale, dar ați fi un dezvoltator de noduri mult mai bun dacă sunteți cel puțin puțin familiarizat cu biblioteca sa standard înainte de a verifica ce are de oferit comunitatea.

Am un alt tutorial care acoperă crearea unui site web Node.js folosind Express ca server web și Mops pentru modelare. Puteți verifica dacă doriți mai multă practică cu construirea proiectelor Node și abonați-vă la newsletter-ul meu să primesc notificări când public noi tutoriale.

Publicat inițial la boboc.tech pe 22 noiembrie 2018.