This is an old revision of the document!


Sesiuna 3 - Implementarea unui serviciu CRUD simplu

Scopul sedintei:

  • Realizarea unui REST API in NodeJS
  • Interactiunea cu o baza de date PostgreSQL
  • Realizarea actiunilor CRUD peste un set de date

Resurse

Puteti pleca de la urmatorul schelet de cod. Sunt implementate urmatoarele:

Un REST API poate fi structurat, cel mai des, in doua moduri:

  1. in functie de context
  2. in functie de functionalitate

Noi am ales o impartire bazata pe context. Fiecare context din cadrul serviciului are propriul lui folder (de exemplu, folderul authors). O impartire pe functionalitate implica foldere dedicate functionaltiatilor (de exemplu, folder controllers, folder services, etc…).

Scriptul de start (start.js)

In scriptul de start se initializeaza serverul. Deoarece express se bazeaza pe conceptul de middlewares, adica lanturi de functii, initializarea nu inseamna nimic mai mult decat mai multe functii ale unor pachete puse impreuna, la inceput.

const express = require('express'); // pachet folosit pentru partea de REST API server
const morgan = require('morgan'); // pachet folosit pentru formatarea log-urilor
const helmet = require('helmet'); // pachet folosit pentru adaugarea unor headere de securitate
const createError = require('http-errors'); // pachet folosit pentru trimiterea de erori
 
require('express-async-errors'); // pachet folosit pentru captarea erorilor pe rute
require('log-timestamp'); // pachet folosit pentru injectarea timpului in momenul in care se da console.log()
 
const routes = require('./routes.js'); // fisierul (scris de noi) care are configurate toate rutele
 
const app = express(); // instantierea serverului efectiv
 
app.use(helmet()); // adaugarea primului middleware, cel oferit de pachetul helmet
app.use(morgan(':remote-addr - :remote-user [:date[web]] ":method :url HTTP/:http-version" :status :res[content-length]')); // adaugarea celui de-al doilea middleware, cel oferit de pachetul morgan
app.use(express.json()); // adaugarea celui de-al treilea middleware, cel care extrage obiecte JSON din corpul cererilor. Util pentru POST si PUT
app.use(express.urlencoded({ extended: false })); // adaugarea celui de-al patrulea middleware, cel care extrage obiecte x-www-urlencoded din corpul cererilor. Util pentru POST si PUT, daca nu se foloseste JSON
 
app.use('/api', routes); // adaugarea rutelor configurate de noi in lantul de rute, cu radacina /api
 
app.use((err, req, res, next) => {
    console.error(err);
    let status = 500;
    let message = 'Something Bad Happened';
    if (err.httpStatus) {
        status = err.httpStatus;
        message = err.message;
    } 
    return next(createError(status, message));
}); // adaugarea unui middleware ce intercepteaza erorile si foloseste createError pentru incapsularea lor
 
 
const port = process.env.PORT || 80; // stabilirea portului pe care va rula serverul in functie de variabila de mediu. Daca nu exista, este implicit 80
 
app.listen(port, () => {
    console.log(`App is listening on ${port} and running on ${process.env.NODE_ENV} mode`);
}); // deschiderea serverului pe portul stabilit

Fisierul de configurare al rutelor (routes.js)

Acest fisier are rol de a centraliza toate controllerele folosite in aplicatie si de a le servi sub forma unui obiect Router care este, apoi, consumat in start.js.

const Router = require('express').Router(); // instantierea obiectului Router din biblioteca express. Ajuta la rutare modulara
 
const authorsControllers = require('./authors/controllers.js'); // controllerul folosit pentru autori
 
Router.use('/authors', authorsControllers); // adaugarea controllerului de autori in rutele obiectului Router, cu radacina /authors
 
module.exports = Router; // expunerea obiectului Router pentru a putea fi folosit de alte fisiere. Bineinteles, dupa cum ati vazut, este folosit in start.js

Interactiunea cu baza de date (data/index.js)

Baza de date este PostgreSQL, asa ca, pentru interactiune, am utilizat un driver facut pentru NodeJS, care se numeste pg. PG ofera posibilitatea scrierii de cereri SQL ad-hoc. Se puteau folosi si alte pachete, care abstractizeaza acest proces, precum Knex.js, insa, pentru simplitate, am optat pe SQL “de mana”.

Scopul acestui fisier este de a initializa conexiunea cu baza de date si de a oferi, catre public, o functie (query) prin care se pot trimite cereri SQL catre baza de date.

const {
    Pool
  } = require('pg'); // preluarea obiectului Pool din pachetul pg care initializeaza conexiunea cu baza de date
 
  const {
    getSecret
  } = require('docker-secret'); // folosit mai tarziu, o sa vedeti ;)
 
  const options = {
    host: process.env.PGHOST,
    database: process.env.PGDATABASE,
    port: process.env.PGPORT,
    user: process.env.NODE_ENV === 'development' ? process.env.PGUSER : getSecret(process.env.PGUSER_FILE),
    password: process.env.NODE_ENV === 'development' ? process.env.PGPASSWORD : getSecret(process.env.PGPASSWORD_FILE)
  } // preluarea informatiilor de conectare din variabilele de mediu
 
  const pool = new Pool(options); // realizarea conexiunii folosind informatiile de conectare si obiectul Pool
 
  const query = async (text, params) => {
    const {
      rows,
    } = await pool.query(text, params);
    return rows;
  }; // crearea functiei de interactiune cu baza de date. Functia are doi parametri, un string, care reprezinta cererea SQL si un vector de valori, din care sunt preluate valorile si injectate in cerere.
 
  module.exports = {
    query,
  }; // expunerea functiei
moby/backend/03.1595505308.txt.gz · Last modified: 2020/07/23 14:55 by alexandru.hogea
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0