Fermer

novembre 22, 2019

Débuter avec une pile Express et ES6 + JavaScript


À propos de l'auteur

Jamie est un développeur Full Stack de 16 ans situé au Texas. Il s'intéresse particulièrement à l'enseignement, à l'apprentissage automatique et à la vision par ordinateur, et…
Plus d'informations sur
Jamie

Introduction de base au processus de développement d'applications Web d'arrière-plan avec Express: présentation des fonctionnalités JavaScript ES6 + à la pointe de la technologie, du modèle de conception d'usine, des opérations MongoDB CRUD, des serveurs et des ports, et du futur, avec des modèles d'architecture n-tier d'entreprise pour les projets TypeScript.

Cet article est la deuxième partie d’une série, dont la première est située ici et qui fournit un aperçu de base et (espérons-le) intuitif de Node.js, ES6 + JavaScript, Fonctions de rappel, Arrow Fonctions, API, protocole HTTP, JSON, MongoDB, etc.

Dans cet article, nous nous appuyons sur les compétences acquises précédemment, sur la mise en œuvre et le déploiement d'une base de données MongoDB pour stocker les informations de la liste de lecture utilisateur. , construisez une API avec Node.js et la structure Express Web Application pour exposer cette base de données et effectuer des opérations CRUD dessus, etc. En cours de route, nous aborderons la destruction d’objet ES6, la synthèse d’objet ES6, la syntaxe Async / Await, l’opérateur Spread, puis un bref aperçu de la CORS, de la stratégie de même origine et plus encore.

Dans un article ultérieur, nous allons reformuler notre base de code afin de séparer les problèmes en utilisant une architecture à trois couches et en obtenant l'inversion du contrôle via l'injection de dépendance. Nous effectuerons la sécurité basée sur l'authentification par jeton Web JSON et l'authentification Firebase et apprendrons comment stocker en toute sécurité les mots de passe. et emploie AWS Simple Storage Service pour stocker les avatars des utilisateurs avec les tampons et les flux Node.js, tout en utilisant PostgreSQL pour la persistance des données. En cours de route, nous réécrirons notre base de code à partir de zéro dans TypeScript afin d'examiner les concepts classiques de la programmation orientée objet (tels que Polymorphisme, Héritage, Composition, etc.) et même de concevoir des modèles tels que Factories et Adapters.

Of Warning

Il existe un problème avec la majorité des articles traitant de Node.js sur le marché aujourd'hui. La plupart d'entre elles, pas toutes, ne vont pas plus loin que la description de la configuration du routage express, de l'intégration de Mongoose et éventuellement de l'utilisation de l'authentification par jeton Web JSON. Le problème est qu’ils ne parlent ni d’architecture, ni de meilleures pratiques en matière de sécurité, ni de principes de codage propres, ni de conformité ACID, de bases de données relationnelles, de cinquième forme normale, du théorème CAP ou de Transactions. On suppose soit que vous êtes au courant de tout ce qui va arriver, soit que vous ne construirez pas de projets assez grands ou suffisamment populaires pour justifier les connaissances susmentionnées.

Il semble exister différents types de développeurs de nœuds, parmi lesquels: certains sont nouveaux dans la programmation en général, et d'autres proviennent d'une longue histoire de développement d'entreprise avec C # et le .NET Framework ou le Java Spring Framework. La majorité des articles s’adressent à l’ancien groupe.

Dans cet article, je vais faire exactement ce que je viens de dire: trop d’articles sont en cours, mais dans un article de suivi, nous allons entièrement refactoriser notre base de code. , me permettant d’expliquer des principes tels que l’injection de dépendance, l’architecture à trois couches (contrôleur / service / référentiel), le mappage de données et l’enregistrement actif, les modèles de conception, les tests unitaires, d’intégration et de mutation, les principes SOLID, l’unité de travail, le codage par rapport aux interfaces , les meilleures pratiques de sécurité telles que HSTS, CSRF, NoSQL et Prévention d’injection SQL, etc. Nous migrerons également de MongoDB vers PostgreSQL, en utilisant le constructeur de requêtes simple Knex au lieu d’un ORM – nous permettant de construire notre propre infrastructure d’accès aux données et de nous rapprocher et de nous familiariser avec le langage de requête structurée, les différents types de relations (Un). à un, plusieurs à plusieurs, etc.), et plus. Cet article devrait donc intéresser les débutants, mais les prochains articles devraient s'adresser à un plus grand nombre de développeurs de niveau intermédiaire cherchant à améliorer leur architecture.

Dans cet article, nous ne nous préoccuperons que de la persistance des données de livre. Nous ne nous occuperons pas de l’authentification de l’utilisateur, du hachage de mot de passe, de l’architecture, ni de ce genre de complexe Tout cela viendra dans les articles suivants et à venir. Pour l'instant, nous allons simplement créer une méthode permettant à un client de communiquer avec notre serveur Web via le protocole HTTP afin de sauvegarder les informations du livre dans une base de données.

Remarque : J'ai délibérément gardé la chose extrêmement simple et peut-être pas très pratique ici car cet article, en soi, est extrêmement long, car je me suis permis de m'éloigner pour discuter de sujets supplémentaires. Ainsi, nous améliorerons progressivement la qualité et la complexité de l'API sur cette série, mais encore une fois, parce que je considère cela comme l'une de vos premières introductions dans Express, je garde intentionnellement les choses extrêmement simples.

  1. ES6 Object Destructuring
  2. Objet abrégé ES6
  3. Opérateur de propagation ES6 (…)
  4. À venir …

Destruction d'objet ES6

La syntaxe d'attribution d'objet de destruction d'objet ES6

est une méthode permettant d'extraire ou décompressez les valeurs des tableaux ou des objets dans leurs propres variables. Nous commencerons par les propriétés d’objet, puis nous discuterons des éléments de tableau.

 const person = {
    nom: 'Richard P. Feynman',
    profession: 'physicien théorique'
};

// Propriétés du journal:
console.log ('Nom:', personne.nom);
console.log ('Occupation:', person.occupation); 

Une telle opération est assez primitive, mais il peut être un peu fastidieux de penser que nous devons continuer à faire référence à personne.quelque chose partout. Supposons qu'il y ait 10 autres endroits dans notre code où nous devions faire cela – cela deviendrait assez pénible assez rapidement. Une méthode de brièveté consisterait à affecter ces valeurs à leurs propres variables.

 const person = {
    nom: 'Richard P. Feynman',
    profession: 'physicien théorique'
};

const personName = person.name;
const personOccupation = person.occupation;

// Propriétés du journal:
console.log ('Nom:', personName);
console.log ('Occupation:', personOccupation); 

Cela semble peut-être raisonnable, mais que se passerait-il si 10 autres propriétés étaient également imbriquées dans l'objet personne ? Ce serait beaucoup de lignes inutiles juste pour assigner des valeurs à des variables – à quel point nous sommes en danger parce que si les propriétés de l'objet sont mutées, nos variables ne refléteront pas ce changement (rappelez-vous, seules les références à l'objet sont immuables avec const pas les propriétés de l'objet), donc, fondamentalement, nous ne pouvons plus garder «état» (et j'utilise ce mot vaguement) de manière synchrone. Passer par référence vs passer par valeur pourrait entrer en jeu ici, mais je ne veux pas trop m'éloigner de la portée de cette section.

ES6 La destruction d'objet nous permet essentiellement de faire ceci:

 const person = {
    nom: 'Richard P. Feynman',
    profession: 'physicien théorique'
};

// C'est nouveau. C'est ce qu'on appelle la destruction d'objet.
const {nom, profession} = personne;

// Propriétés du journal:
console.log ('Nom:', nom);
console.log ('Occupation:', occupation); 

Nous ne sommes pas en train de créer un nouvel objet / objet littéral, nous déballons le nom les noms et ] propriétés de l'objet d'origine et en les plaçant dans leurs propres variables du même nom. Les noms que nous utilisons doivent correspondre aux noms de propriété que nous souhaitons extraire.

Encore une fois, la syntaxe const {a, b} = someObject; indique spécifiquement que nous attendons une propriété a et quelques biens b exister dans une partie de l'Objet (c'est-à-dire, une partie de l'objet pourrait être {a: 'dataA', b: 'dataB' } par exemple) et que nous voulons placer quelles que soient les valeurs de ces clés / propriétés dans des variables const du même nom. C'est pourquoi la syntaxe ci-dessus nous fournirait deux variables const a = someObject.a et const b = someObject.b .

Cela signifie qu'il y a deux côtés à Destructuration d'objets. Le côté «Modèle» et le côté «Source», où le côté const {a, b} (à gauche) correspond au modèle et le someObject (côté droit) correspond au côté source – ce qui est logique – nous définissons une structure ou un "modèle" à gauche qui reflète les données du côté "source".

Encore une fois, juste pour que ce soit clair, voici quelques exemples:

 // ----- Destructure à partir d'une variable d'objet avec const ----- //
const objOne = {
    a: 'dataA',
    b: 'dataB'
};

// destruction
const {a, b} = objOne;

console.log (a); // dataA
console.log (b); // dataB

// ----- Destructure à partir d'une variable d'objet avec let ----- //
laissez objTwo = {
    c: 'dataC',
    d: 'dataD'
};

// destruction
Soit {c, d} = objTwo;

console.log (c); // dataC
console.log (d); // dataD

// Destructure à partir du littéral d'objet avec const ----- //
const {e, f} = {e: 'dataE', f: 'dataF'}; // 

Dans le cas de propriétés imbriquées, reproduisez la même structure dans votre tâche de destruction:

 const person = {
    nom: 'Richard P. Feynman',
    Occupation: {
        type: 'physicien théorique',
        emplacement: {
            lat: 1,
            lng: 2
        }
    }
};

// essayer un:
const {nom, profession} = personne;

console.log (nom); // Richard P. Feynman
console.log (occupation); // Tout l'objet `occupation`.

// Essayez deux:
const {occupation: {type, location}} = personne;

console.log (type); // Physicien théoricien
console.log (location) // L'objet entier `location`.

// essayer trois:
const {occupation: {location: {lat, nng}}} = personne;

console.log (lat); // 1
console.log (lng); // 2 

Comme vous pouvez le constater, les propriétés que vous décidez d'extraire sont facultatives. Pour décompresser les propriétés imbriquées, mettez simplement en miroir la structure de l'objet d'origine (la source) dans la partie modèle de votre syntaxe de déstructuration. Si vous tentez de déstructurer une propriété qui n'existe pas sur l'objet d'origine, cette valeur sera indéfinie.

Nous pouvons également déstructurer une variable sans la déclarer au préalable – affectation sans déclaration – à l'aide de la syntaxe suivante:

 let name , Occupation;

const personne = {
    nom: 'Richard P. Feynman',
    profession: 'physicien théorique'
};

; ({nom, profession} = personne);

console.log (nom); // Richard P. Feynman
console.log (occupation); // Physicien théoricien 

Nous précédons l'expression par un point-virgule afin de ne pas créer accidentellement une IIFE (expression de fonction immédiatement appelée) avec une fonction sur une ligne précédente (si une telle fonction existe) et les parenthèses autour les instructions d'affectation sont nécessaires pour empêcher JavaScript de traiter votre partie gauche (modèle) comme un bloc.

Un cas très courant d'utilisation de la déstructuration existe dans les arguments de la fonction:

 const config = {
    baseUrl: '',
    awsBucket: '',
    secret: '' // <- Make this an env var.
};

// Destructures `baseUrl` and `awsBucket` off `config`.
const performOperation = ({ baseUrl, awsBucket }) => {
    fetch (baseUrl) .then (() => console.log ('Terminé'));
    console.log (awsBucket); // 
};

performOperation (config); 

Comme vous pouvez le constater, nous aurions pu utiliser la syntaxe de déstructuration normale à laquelle nous sommes maintenant habitués à l'intérieur de la fonction, comme ceci:

 const config = {
    baseUrl: '',
    awsBucket: '',
    secret: '' // <- Make this an env var.
};

const performOperation = someConfig => {
    const {baseUrl, awsBucket} = someConfig;
    fetch (baseUrl) .then (() => console.log ('Terminé'));
    console.log (awsBucket); // 
};

performOperation (config); 

Mais le fait de placer ladite syntaxe dans la signature de la fonction effectue automatiquement la déstructuration et nous enregistre une ligne.

Un exemple d'utilisation pratique de ceci est dans React Functional Components pour props :

 import Réagit de 'réagir';

// détruit `titleText` et` secondaryText` de `props`.
export default ({titleText, secondaryText}) => (
    

{titleText}

{secondaryText}

)

Contrairement à:

 import Réagissez à partir de 'react';

exporter les accessoires par défaut => (
    

{props.titleText}

{props.secondaryText}

)

Dans les deux cas, nous pouvons également définir des valeurs par défaut pour les propriétés:

 const personOne = {
    nom: 'User One',
    mot de passe: 'BCrypt Hash'
};

const personTwo = {
    mot de passe: 'BCrypt Hash'
};

const createUser = ({name = 'Anonymous', mot de passe}) => {
    if (! mot de passe) renvoie une nouvelle erreur ('InvalidArgumentException');
    
    console.log (nom);
    console.log (mot de passe);
    
    revenir {
        id: Math.random (). toString (36) // 

Comme vous pouvez le constater, dans le cas où name n'est pas présent lors de la déstructuration, nous lui fournissons une valeur par défaut. Nous pouvons également le faire avec la syntaxe précédente:

 const {a, b, c = 'Défaut'} = {a: 'dataA', b: 'dataB'};
console.log (a); // dataA
console.log (b); // dataB
console.log (c); // Défaut 

Les tableaux peuvent aussi être déstructurés:

 const myArr = [4, 3];

// La destruction se produit ici.
const [valOne, valTwo] = myArr;

console.log (valOne); // 4
console.log (valTwo); // 3

// ----- Destructuration sans affectation: ----- //
laissez a, b;

// La destruction se produit ici.
; ([a, b] = [10, 2]);

console.log (a + b); // 12 

Une raison pratique pour la déstructuration du tableau se trouve avec les crochets à réaction. (Et il y a beaucoup d'autres raisons, j'utilise juste React à titre d'exemple).

 import React, {useState} de "react";

export default () => {
  const [buttonText, setButtonText] = useState ("Par défaut");

  revenir (
    
  )
} 

Notice useState est en cours de destruction de l'exportation et les fonctions / valeurs du tableau sont en cours de destruction du crochet useState . Encore une fois, ne vous inquiétez pas si ce qui précède n'a pas de sens – vous devez comprendre React – et je l'utilise simplement à titre d'exemple.

Bien qu'il y ait plus que la destruction d'objets ES6, je vais couvrir un autre sujet ici: Destructuring Renaming, ce qui est utile pour éviter les collisions de portée, les ombres variables, etc. Supposons que nous voulions déstructurer une propriété appelée nom à partir d'un objet appelé personne mais il y a est déjà une variable du nom de nom . On peut renommer à la volée avec deux points:

 // Exemple de collision de nommage de destruction JS:
nom de const = 'Jamie Corkhill';

const personne = {
    nom: 'Alan Touring'
};

// Renomme `name` de` person` en `personName` après la déstructuration.
const {name: personName} = person;

console.log (nom); // Jamie Corkhill 

Enfin, nous pouvons également définir les valeurs par défaut en renommant:

 const name = 'Jamie Corkhill';

const personne = {
    lieu: 'New York City, États-Unis'
};

const {name: personName = 'Anonymous', location} = personne;

console.log (nom); // Jamie Corkhill
console.log (personName); // anonyme
console.log (emplacement); // New York, États-Unis 

Comme vous pouvez le voir, dans ce cas, nom de personne ( personne.nom ) sera renommé en personName et définissez la valeur par défaut de Anonyme si inexistant.

Et bien entendu, la même chose peut être effectuée dans les signatures de fonction:

 const personOne = {
    nom: 'User One',
    mot de passe: 'BCrypt Hash'
};

const personTwo = {
    mot de passe: 'BCrypt Hash'
};

const createUser = ({name: personName = 'Anonymous', mot de passe}) => {
    if (! mot de passe) renvoie une nouvelle erreur ('InvalidArgumentException');
    console.log (personName);
    console.log (mot de passe);

    revenir {
        id: Math.random (). toString (36). Substring (2, 15) + Math.random (). toString (36). Substring (2, 15),
        nom: personName,
        password: password // 

ES6 Object Shorthand

Supposons que vous avez l’usine suivante: (nous couvrirons les usines plus tard)

 const createPersonFactory = (nom, emplacement, position) => {
    nom nom,
    emplacement: emplacement,
    position: position

On pourrait utiliser cette usine pour créer un objet personne comme suit. Notez également que la fabrique renvoie implicitement un objet, ce qui est évident entre parenthèses entre les crochets de la fonction flèche.

 const person = createPersonFactory ('Jamie', 'Texas', 'Developer');
console.log (personne); // {...} 

C’est ce que nous savons déjà de la syntaxe de la litière d’objets de l’ES5. Notez cependant, dans la fonction factory, que la valeur de chaque propriété porte le même nom que l'identificateur de la propriété (clé) elle-même. C'est-à-dire – emplacement: emplacement ou nom: nom . Il s'est avéré que c'était assez courant avec les développeurs JS.

Avec la syntaxe abrégée de ES6, nous pouvons obtenir le même résultat en réécrivant la fabrique comme suit:

 const createPersonFactory = (nom, emplacement, position) => ({
    prénom,
    emplacement,
    position
});

const person = createPersonFactory ('Jamie', 'Texas', 'Developer');
console.log (personne); 

Production de la sortie:

 {nom: 'Jamie', emplacement: 'Texas', position: 'Développeur'} 

Il est important de réaliser que nous ne pouvons utiliser que ce raccourci. lorsque l'objet que nous souhaitons créer est créé dynamiquement en fonction de variables, où les noms de variable sont identiques à ceux des propriétés auxquelles nous voulons attribuer les variables.

Cette syntaxe est identique à celle utilisée valeurs d'objet:

 const createPersonFactory = (nom, emplacement, position, extra) => ({
    prénom,
    emplacement,
    position,
    extra // 

Production de la sortie:

 {
    nom: 'Jamie',
    lieu: 'Texas',
    position: 'Développeur',
    supplémentaire: {
        intérêts: [ 
            'Mathematics',
            'Quantum Mechanics',
            'Spacecraft Launch Systems' 
        ],
        langue préférée: [ 'JavaScript', 'C#' ]
     }
} 

Comme dernier exemple, cela fonctionne également avec les littéraux d'objet:

 const id = '314159265358979';
const name = 'Archimède de Syracuse';
emplacement de const = 'Syracuse';

const greatMathematician = {
    identifiant,
    prénom,
    emplacement

ES6 Spread Operator (…)

L'opérateur Spread nous permet de faire diverses choses, dont certaines sont discutées ici.

Premièrement, nous pouvons étaler les propriétés d'un objet. sur un autre objet:

 const myObjOne = {a: 'a', b: 'b'};
const myObjTwo = {... myObjOne}: 

Ceci a pour effet de placer toutes les propriétés sur myObjOne sur myObjTwo telles que myObjTwo est maintenant {a: 'a', b: 'b'} . Nous pouvons utiliser cette méthode pour remplacer les propriétés précédentes. Supposons qu'un utilisateur souhaite mettre à jour son compte:

 const user = {
    nom: 'John Doe',
    email: 'john@domain.com',
    mot de passe: '',
    bio: 'Lorem ipsum'
};

const updates = {
    mot de passe: '',
    bio: 'Ipsum lorem',
    email: 'j@domain.com'
};

const updatedUser = {
    ... utilisateur, // ', // mis à jour
     bio: 'Ipsum lorem'
 }
 * /   

La même chose peut être effectuée avec des tableaux:

 const apollo13Astronauts = ['Jim', 'Jack', 'Fred'];
const apollo11Astronauts = ['Neil', 'Buz', 'Michael'];

const unionOfAstronauts = [...apollo13Astronauts, ...apollo11Astronauts];

console.log (unionOfAstronauts);
// ['Jim', 'Jack', 'Fred', 'Neil', 'Buz, 'Michael']; 

Notez ici que nous avons créé une union des deux ensembles (tableaux) en répartissant les tableaux dans un nouveau tableau.

L'opérateur Rest / Spread en a bien plus à offrir, mais hors de portée pour cet article. Il peut être utilisé pour obtenir plusieurs arguments pour une fonction, par exemple. Si vous souhaitez en savoir plus, consultez la documentation MDN ici .

ES6 Async / Await

Async / Await est une syntaxe permettant d'atténuer les difficultés d'enchaînement des promesses.

Le




Source link