Catégories
Plugin et site web

Création d'applications frontales sans serveur à l'aide de Google Cloud Platform – Smashing Magazine

A propos de l'auteur

Nwani Victory travaille en tant qu'ingénieur Frontend chez Liferithms.inc de Lagos, au Nigeria. Après les heures de bureau, il se double d'un ingénieur cloud à la recherche de moyens de faire du cloud…
Plus à propos
Nwani

L'utilisation d'applications sans serveur par les développeurs pour gérer la logique métier de leurs applications est en forte augmentation, mais comment Google Cloud – un fournisseur de services majeur du cloud public – permet-il aux développeurs de gérer des applications sans serveur? Dans cet article, vous découvrirez ce que sont les applications sans serveur, comment elles sont utilisées sur Google Cloud, ainsi que les scénarios dans lesquels elles peuvent être utilisées dans une application frontale.

Récemment, le paradigme de développement des applications a commencé à passer de l'obligation manuelle de déployer, de mettre à l'échelle et de mettre à jour les ressources utilisées dans une application à s'appuyer sur des fournisseurs de services cloud tiers pour assurer la plupart de la gestion de ces ressources.

En tant que développeur ou organisation souhaitant créer une application adaptée au marché dans les plus brefs délais, votre objectif principal peut être de fournir votre service d'application principal à vos utilisateurs, tandis que vous passez moins de temps à configurer, déployer et tester les contraintes. ton application. Si tel est votre cas d'utilisation, la gestion de la logique métier de votre application sans serveur est la meilleure option. Mais comment?

Cet article est utile aux ingénieurs front-end qui souhaitent créer certaines fonctionnalités au sein de leur application ou aux ingénieurs back-end qui souhaitent extraire et gérer une certaine fonctionnalité d'un service back-end existant à l'aide d'une application sans serveur déployée sur Google Cloud Platform.

Remarque: Pour bénéficier de ce qui sera couvert ici, vous devez avoir une expérience de travail avec React. Aucune expérience préalable des applications sans serveur n'est requise.

Avant de commencer, voyons ce que sans serveur les applications sont vraiment et comment l'architecture sans serveur peut être utilisée lors de la construction d'une application dans le contexte d'un ingénieur front-end.

Applications sans serveur

Les applications sans serveur sont des applications décomposées en de minuscules fonctions événementielles réutilisables, hébergées et gérées par des fournisseurs de services cloud tiers dans le cloud public pour le compte de l'auteur de l'application. Celles-ci sont déclenchées par certains événements et sont exécutées à la demande. Bien que le "Moins"Suffixe attaché au sans serveur mot indique l'absence de serveur, ce n'est pas à 100% le cas. Ces applications fonctionnent toujours sur des serveurs et d'autres ressources matérielles, mais dans ce cas, ces ressources ne sont pas fournies par le développeur mais plutôt par un fournisseur de services cloud tiers. Donc ils sont serveur-Moins à l'auteur de l'application, mais fonctionnent toujours sur des serveurs et sont accessibles sur Internet public.

Un exemple de cas d'utilisation d'une application sans serveur serait l'envoi d'e-mails à des utilisateurs potentiels qui visitent votre page de destination et s'abonnent pour recevoir des e-mails de lancement de produit. À ce stade, vous n'avez probablement pas de service back-end en cours d'exécution et ne voudriez pas sacrifier le temps et les ressources nécessaires pour en créer, déployer et gérer un, tout cela parce que vous devez envoyer des e-mails. Ici, vous pouvez écrire un fichier unique qui utilise un client de messagerie et le déployer sur n'importe quel fournisseur de cloud prenant en charge les applications sans serveur et les laisser gérer cette application en votre nom pendant que vous connectez cette application sans serveur à votre page de destination.

Bien qu'il existe une tonne de raisons pour lesquelles vous pourriez envisager de tirer parti des applications sans serveur ou des fonctions en tant que service (FAAS) comme on les appelle, pour votre application frontale, voici quelques raisons très notables que vous devriez considérer:

  • Mise à l'échelle automatique des applications
    Les applications sans serveur sont mises à l'échelle horizontalement et ceci "mise à l'échelle"Est automatiquement effectué par le fournisseur de cloud en fonction du nombre d'appels, de sorte que le développeur n'a pas à ajouter ou supprimer manuellement des ressources lorsque l'application est soumise à une charge importante.
  • Rentabilité
    Les applications sans serveur, pilotées par les événements, ne s'exécutent qu'en cas de besoin, ce qui se répercute sur les frais, car elles sont facturées en fonction du nombre de fois appelées.
  • Souplesse
    Les applications sans serveur sont conçues pour être hautement réutilisables, ce qui signifie qu'elles ne sont pas liées à un seul projet ou application. Une fonctionnalité particulière peut être extraite dans une application sans serveur, déployée et utilisée dans plusieurs projets ou applications. Les applications sans serveur peuvent également être écrites dans la langue préférée de l'auteur de l'application, bien que certains fournisseurs de cloud ne prennent en charge qu'un plus petit nombre de langues.

Lorsqu'il utilise des applications sans serveur, chaque développeur dispose d'un vaste éventail de fournisseurs de cloud dans le cloud public à utiliser. Dans le contexte de cet article, nous nous concentrerons sur les applications sans serveur sur la plate-forme Google Cloud – comment elles sont créées, gérées, déployées et comment elles s'intègrent également à d'autres produits sur Google Cloud. Pour ce faire, nous ajouterons de nouvelles fonctionnalités à cette application React existante tout en travaillant sur le processus de:

  • Stocker et récupérer les données des utilisateurs sur le cloud;
  • Créer et gérer des tâches cron sur Google Cloud;
  • Déploiement de Cloud Functions sur Google Cloud.

Remarque: Les applications sans serveur ne sont pas liées uniquement à React, tant que votre infrastructure frontale ou bibliothèque préférée peut créer un HTTP demande, il peut utiliser une application sans serveur.

Fonctions Google Cloud

Google Cloud permet aux développeurs de créer des applications sans serveur à l'aide des fonctions Cloud Functions et de les exécuter à l'aide du framework Functions. Comme on les appelle, les fonctions cloud sont des fonctions événementielles réutilisables déployées sur Google Cloud pour écouter un déclencheur spécifique parmi les six déclencheurs d'événements disponibles, puis effectuer l'opération pour laquelle elles ont été écrites.

Fonctions cloud de courte durée, (avec un délai d'exécution par défaut de 60 secondes et un maximum de 9 minutes) peuvent être écrits en utilisant JavaScript, Python, Golang et Java et exécutés en utilisant leur runtime. En JavaScript, ils peuvent être exécutés en utilisant uniquement certaines versions disponibles du runtime Node et sont écrits sous la forme de modules CommonJS à l'aide de JavaScript brut, car ils sont exportés en tant que fonction principale à exécuter sur Google Cloud.

Un exemple de fonction cloud est celui ci-dessous qui est un passe-partout vide pour la fonction permettant de gérer les données d'un utilisateur.

// index.js

exports.firestoreFunction = function (req, res) {
  return res.status(200).send({ data: `Hello ${req.query.name}` });
}

Ci-dessus, nous avons un module qui exporte une fonction. Lorsqu'il est exécuté, il reçoit les arguments de demande et de réponse similaires à un HTTP route.

Remarque: Une fonction cloud correspond à chaque HTTP protocole lorsqu'une demande est faite. Cela vaut la peine d'être noté lors de l'attente de données dans l'argument de requête, car les données jointes lors d'une requête pour exécuter une fonction cloud seraient présentes dans le corps de la requête pour POST requêtes dans le corps de la requête pour GET demandes.

Les fonctions cloud peuvent être exécutées localement pendant le développement en installant le @google-cloud/functions-framework package dans le même dossier où la fonction écrite est placée ou effectuer une installation globale pour l'utiliser pour plusieurs fonctions en exécutant npm i -g @google-cloud/functions-framework depuis votre ligne de commande. Une fois installé, il doit être ajouté au package.json script avec le nom du module exporté similaire à celui ci-dessous:

"scripts": {                                                                
     "start": "functions-framework --target=firestoreFunction --port=8000",       
  }

Ci-dessus, nous avons une seule commande dans nos scripts dans le package.json fichier qui exécute le framework de fonctions et spécifie également le firestoreFunction comme fonction cible à exécuter localement sur le port 8000.

Nous pouvons tester le point de terminaison de cette fonction en faisant un GET demande de port 8000 sur localhost en utilisant curl. Coller la commande ci-dessous dans un terminal le fera et retournera une réponse.

curl http://localhost:8000?name="Smashing Magazine Author"

La commande ci-dessus fait une demande avec un GET HTTP méthode et répond par un 200 code d'état et données d'objet contenant le nom ajouté dans la requête.

Déployer une fonction cloud

Parmi les méthodes de déploiement disponibles, un moyen rapide de déployer une fonction cloud à partir d'une machine locale consiste à utiliser le cloud Sdk après son installation. L'exécution de la commande ci-dessous à partir du terminal après avoir authentifié le sdk gcloud avec votre projet sur Google Cloud déploierait une fonction créée localement sur le service Cloud Function.

gcloud functions deploy "demo-function" --runtime nodejs10 --trigger-http --entry-point=demo --timeout=60 --set-env-vars=(name="Developer") --allow-unauthenticated

À l'aide des indicateurs expliqués ci-dessous, la commande ci-dessus déploie une fonction déclenchée HTTP sur le cloud Google avec le nom "fonction de démonstration».

  • NOM
    Il s'agit du nom donné à une fonction cloud lors de son déploiement et est obligatoire.
  • region
    Il s'agit de la région dans laquelle la fonction cloud doit être déployée. Par défaut, il est déployé sur us-central1.
  • trigger-http
    Cela sélectionne HTTP comme type de déclencheur de la fonction.
  • allow-unauthenticated
    Cela permet à la fonction d'être appelée en dehors de Google Cloud via Internet en utilisant son point de terminaison généré sans vérifier si l'appelant est authentifié.
  • source
    Chemin local du terminal vers le fichier contenant la fonction à déployer.
  • entry-point
    Il s'agit du module exporté spécifique à déployer à partir du fichier dans lequel les fonctions ont été écrites.
  • runtime
    Il s'agit du langage d'exécution à utiliser pour la fonction parmi cette liste d'exécutables acceptés.
  • timeout
    Il s'agit de la durée maximale pendant laquelle une fonction peut s'exécuter avant l'expiration du délai. Il est de 60 secondes par défaut et peut être réglé sur un maximum de 9 minutes.

Remarque: Faire en sorte qu'une fonction autorise les requêtes non authentifiées signifie que toute personne disposant du point de terminaison de votre fonction peut également effectuer des requêtes sans que vous ne les accordiez. Pour atténuer cela, nous pouvons nous assurer que le point de terminaison reste privé en l'utilisant via des variables d'environnement ou en demandant des en-têtes d'autorisation à chaque demande.

Maintenant que notre fonction de démonstration a été déployée et que nous avons le point final, nous pouvons tester cette fonction comme si elle était utilisée dans une application du monde réel en utilisant une installation globale d'autocanon. Fonctionnement autocannon -d=5 -c=300 CLOUD_FUNCTION_URL à partir du terminal ouvert générerait 300 requêtes simultanées à la fonction cloud en 5 secondes. C'est plus que suffisant pour démarrer la fonction cloud et générer également des métriques que nous pouvons explorer sur le tableau de bord de la fonction.

Remarque: Le point de terminaison d'une fonction sera imprimé dans le terminal après le déploiement. Si ce n'est pas le cas, exécutez gcloud function describe FUNCTION_NAME depuis le terminal pour obtenir les détails sur la fonction déployée, y compris le point de terminaison.

En utilisant l'onglet métriques sur le tableau de bord, nous pouvons voir une représentation visuelle de la dernière demande consistant en combien d'appels ont été effectués, combien de temps ils ont duré, l'empreinte mémoire de la fonction et combien d'instances ont été lancées pour gérer les demandes effectuées.

Tableau de bord d'une fonction affichant un graphique des métriques collectées à partir de toutes les demandes récentes effectuées.
Tableau de bord de la fonction cloud affichant toutes les demandes effectuées. (Grand aperçu)

Un examen plus approfondi du graphique des instances actives dans l'image ci-dessus montre la capacité de mise à l'échelle horizontale des fonctions cloud, car nous pouvons voir que 209 instances ont été lancées en quelques secondes pour gérer les demandes effectuées à l'aide du canon automatique.

Journaux des fonctions cloud

Chaque fonction déployée sur le cloud Google dispose d'un journal et chaque fois que cette fonction est exécutée, une nouvelle entrée dans ce journal est effectuée. Du Journal dans le tableau de bord de la fonction, nous pouvons voir une liste de toutes les entrées de journaux d'une fonction cloud.

Voici les entrées de journal de notre déploiement demo-function créé à la suite des demandes que nous avons effectuées à l'aide de autocannon.

Le journal de la fonction cloud affichant les journaux des heures d'exécution de la fonction.
Onglet du journal des fonctions cloud affichant tous les journaux d'exécution. (Grand aperçu)

Chacune des entrées de journal ci-dessus montre exactement quand une fonction a été exécutée, combien de temps l'exécution a pris et avec quel code d'état elle s'est terminée. S'il y a des erreurs résultant d'une fonction, les détails de l'erreur, y compris la ligne où elle s'est produite, seront affichés dans les journaux ici.

L'explorateur de journaux sur Google Cloud peut être utilisé pour afficher des détails plus complets sur les journaux à partir d'une fonction cloud.

Fonctions cloud avec applications frontales

Les fonctions cloud sont très utiles et puissantes pour les ingénieurs front-end. Un ingénieur front-end sans connaissance de la gestion des applications back-end peut extraire une fonctionnalité dans une fonction cloud, la déployer sur Google Cloud et l'utiliser dans une application frontale en faisant HTTP demandes à la fonction cloud via son point de terminaison.

Pour montrer comment les fonctions cloud peuvent être utilisées dans une application frontale, nous ajouterons plus de fonctionnalités à cette application React. L'application dispose déjà d'un routage de base entre l'authentification et la configuration des pages d'accueil. Nous l'étendrons pour utiliser l'API React Context pour gérer l'état de notre application, car l'utilisation des fonctions cloud créées se ferait dans les réducteurs d'application.

Pour commencer, nous créons le contexte de notre application à l’aide du createContext API et créez également un réducteur pour gérer les actions au sein de notre application.

// state/index.js
import { createContext } from “react”;

export const UserReducer = (action, state) => { switch (action.type) { case “CREATE-USER”: break; case “UPLOAD-USER-IMAGE”: break; case “FETCH-DATA” : break case “LOGOUT” : break; default: console.log(${action.type} is not recognized) } };

export const userState = { user: null, isLoggedIn : false };

export const UserContext = createContext(userState);

Ci-dessus, nous avons commencé par créer un UserReducer fonction qui contient une instruction switch, lui permettant d'effectuer une opération en fonction du type d'action qui y est envoyée. L'instruction switch a quatre cas et ce sont les actions que nous allons gérer. Pour l'instant, ils ne font encore rien, mais lorsque nous commencerons à intégrer nos fonctions cloud, nous implémenterons de manière incrémentielle les actions à effectuer.

Nous avons également créé et exporté le contexte de notre application à l'aide de l'API React createContext et lui avons donné une valeur par défaut de userState objet qui contient une valeur utilisateur actuellement qui serait mise à jour de null aux données de l'utilisateur après authentification et également un isLoggedIn valeur booléenne pour savoir si l'utilisateur est connecté ou non.

Maintenant, nous pouvons continuer à consommer notre contexte, mais avant de faire cela, nous devons encapsuler toute notre arborescence d'applications avec le fournisseur attaché au UserContext pour que les composants enfants puissent souscrire au changement de valeur de notre contexte.

// index.js 
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./app";
import { UserContext, userState } from "./state/";

ReactDOM.render(
  
    
      
    
  ,
  document.getElementById("root")
);

serviceWorker.unregister();

Nous emballons notre demande d'entrée avec le UserContext fournisseur au niveau du composant racine et passé notre précédemment créé userState valeur par défaut dans la valeur prop.

Maintenant que l'état de notre application est entièrement configuré, nous pouvons passer à la création du modèle de données de l'utilisateur à l'aide de Google Cloud Firestore via une fonction cloud.

Gestion des données d'application

Les données d'un utilisateur dans cette application se composent d'un identifiant unique, d'un e-mail, d'un mot de passe et de l'URL d'une image. À l'aide d'une fonction cloud, ces données seront stockées sur le cloud à l'aide du service Cloud Firestore proposé sur Google Cloud Platform.

le Google Cloud Firestore, une base de données NoSQL flexible a été créée à partir de la base de données Firebase Realtime avec de nouvelles fonctionnalités améliorées qui permettent des requêtes plus riches et plus rapides ainsi que la prise en charge des données hors ligne. Les données du service Firestore sont organisées en collections et documents similaires à d'autres bases de données NoSQL telles que MongoDB.

Le Firestore est accessible visuellement via la console Google Cloud. Pour le lancer, ouvrez le volet de navigation de gauche et faites défiler jusqu'à la section Base de données et cliquez sur Firestore. Cela afficherait la liste des collections pour les utilisateurs avec des données existantes ou inviterait l'utilisateur à créer une nouvelle collection lorsqu'il n'y a pas de collection existante. Nous créerions un utilisateurs collection à utiliser par notre application.

Semblable à d'autres services sur Google Cloud Platform, Cloud Firestore dispose également d'une bibliothèque cliente JavaScript conçue pour être utilisée dans un environnement de nœuds (une erreur sera générée si elle est utilisée dans le navigateur). Pour improviser, nous utilisons le Cloud Firestore dans une fonction cloud en utilisant le @google-cloud/firestore paquet.

Utiliser Cloud Firestore avec une fonction Cloud

Pour commencer, nous renommerons la première fonction que nous avons créée à partir de demo-function à firestoreFunction puis développez-le pour vous connecter au Firestore et enregistrer les données dans la collection de nos utilisateurs.

require("dotenv").config();
const { Firestore } = require("@google-cloud/firestore");
const { SecretManagerServiceClient } = require("@google-cloud/secret-manager");

const client = new SecretManagerServiceClient();
        
exports.firestoreFunction = function (req, res) {
    return {
        const { email, password, type } = req.body;
        const firestore = new Firestore();
        const document = firestore.collection("users");
        console.log(document) // prints details of the collection to the function logs
        if (!type) {
            res.status(422).send("An action type was not specified");
        }

        switch (type) {
            case "CREATE-USER":
                break
            case "LOGIN-USER":
                break;
            default:
                res.status(422).send(`${type} is not a valid function action`)
        }
};

Pour gérer plus d'opérations impliquant le fire-store, nous avons ajouté une instruction switch avec deux cas pour gérer les besoins d'authentification de notre application. Notre instruction switch évalue un type expression que nous ajoutons au corps de la requête lorsque nous faisons une requête à cette fonction depuis notre application et à chaque fois type les données ne sont pas présentes dans le corps de notre demande, la demande est identifiée comme une demande incorrecte et un 400 code d'état à côté d'un message pour indiquer le manquant type est envoyé en réponse.

Nous établissons une connexion avec Firestore à l'aide de la bibliothèque d'Application Default Credentials (ADC) au sein de la bibliothèque cliente Cloud Firestore. Sur la ligne suivante, nous appelons la méthode de collection dans une autre variable et passons le nom de notre collection. Nous allons l'utiliser pour effectuer d'autres opérations sur la collection des documents contenus.

Remarque: Les bibliothèques clientes pour les services sur Google Cloud se connectent à leur service respectif à l'aide d'une clé de compte de service créée transmise lors de l'initialisation du constructeur. Lorsque la clé de compte de service n'est pas présente, elle utilise par défaut les informations d'identification par défaut de l'application qui à leur tour se connectent à l'aide du IAM rôles attribués à la fonction cloud.

Après avoir modifié le code source d'une fonction qui a été déployée localement à l'aide du SDK Gcloud, nous pouvons réexécuter la commande précédente à partir d'un terminal pour mettre à jour et redéployer la fonction cloud.

Maintenant qu'une connexion a été établie, nous pouvons implémenter le CREATE-USER case pour créer un nouvel utilisateur à l'aide des données du corps de la requête.


require("dotenv").config();
const { Firestore } = require("@google-cloud/firestore");
const path = require("path");
const { v4 : uuid } = require("uuid")
const cors = require("cors")({ origin: true });

const client = new SecretManagerServiceClient();

exports.firestoreFunction = function (req, res) {
    return cors(req, res, () => {
        const { email, password, type } = req.body;
        const firestore = new Firestore();
        const document = firestore.collection("users");
        if (!type) {
            res.status(422).send("An action type was not specified");
        }

        switch (type) {
            case "CREATE-USER":
              if (!email || !password) {
                res.status(422).send("email and password fields missing");
              }
            
            const id = uuid()
            return bcrypt.genSalt(10, (err, salt) => {
              bcrypt.hash(password, salt, (err, hash) => {
                document.doc(id)
                  .set({
                    id : id
                    email: email,
                    password: hash,
                    img_uri : null
                   })
                  .then((response) => res.status(200).send(response))
                  .catch((e) =>
                      res.status(501).send({ error : e })
                    );
                  });
                });               

           case "LOGIN":
              break;
          default:
            res.status(400).send(`${type} is not a valid function action`)
        }
    });
};

Nous avons généré un UUID en utilisant le package uuid à utiliser comme ID du document sur le point d'être enregistré en le passant dans le set méthode sur le document et également l’identifiant de l’utilisateur. Par défaut, un ID aléatoire est généré sur chaque document inséré mais dans ce cas, nous mettrons à jour le document lors de la gestion du téléchargement d'image et l'UUID est ce qui sera utilisé pour obtenir un document particulier à mettre à jour. Plutôt que de stocker le mot de passe de l'utilisateur en texte brut, nous le salons d'abord à l'aide de bcryptjs, puis nous stockons le hachage du résultat en tant que mot de passe de l'utilisateur.

Intégrer le firestoreFunction fonction cloud dans l'application, nous l'utilisons à partir du CREATE_USER cas dans le réducteur utilisateur.

Après avoir cliqué sur le Créer un compte bouton, une action est envoyée aux réducteurs avec un CREATE_USER tapez pour faire un POST demande contenant l'e-mail et le mot de passe saisis au firestoreFunction le point de terminaison de la fonction.

import { createContext } from "react";
import { navigate } from "@reach/router";
import Axios from "axios";

export const userState = {
  user : null, 
  isLoggedIn: false,
};

export const UserReducer = (state, action) => {
  switch (action.type) {
    case "CREATE_USER":
      const FIRESTORE_FUNCTION = process.env.REACT_APP_FIRESTORE_FUNCTION;
      const { userEmail, userPassword } = action;

      const data = {
        type: "CREATE-USER",
        email: userEmail,
        password: userPassword,
      };

      Axios.post(`${FIRESTORE_FUNCTION}`, data)
        .then((res) => {
          navigate("/home");
          return { ...state, isLoggedIn: true };
        })
        .catch((e) => console.log(`couldnt create user. error : ${e}`));
      break;
    case "LOGIN-USER":
      break;
    case "UPLOAD-USER-IMAGE":
      break;
    case "FETCH-DATA" :
      break
    case "LOGOUT":
      navigate("/login");
      return { ...state, isLoggedIn: false };
    default:
      break;
  }
};

export const UserContext = createContext(userState);

Ci-dessus, nous avons fait appel à Axios pour faire la demande au firestoreFunction et une fois cette demande résolue, nous définissons l'état initial de l'utilisateur à partir de null aux données renvoyées par la demande et enfin nous acheminons l'utilisateur vers la page d'accueil en tant qu'utilisateur authentifié.

À ce stade, un nouvel utilisateur peut créer avec succès un compte et être dirigé vers la page d'accueil. Ce processus montre comment nous utilisons le Firestore pour effectuer une création de base de données à partir d'une fonction cloud.

Gestion du stockage de fichiers

Le stockage et la récupération des fichiers d’un utilisateur dans une application sont la plupart du temps une fonctionnalité indispensable dans une application. Dans une application connectée à un backend node.js, Multer est souvent utilisé comme middleware pour gérer les données multipart / form dans lesquelles un fichier téléchargé entre. Mais en l'absence du backend node.js, nous pourrions utiliser un fichier en ligne un service de stockage tel que Google Cloud Storage pour stocker des éléments d'application statiques.

Google Cloud Storage est un service de stockage de fichiers disponible dans le monde entier utilisé pour stocker toute quantité de données sous forme d'objets pour les applications dans des buckets. Il est suffisamment flexible pour gérer le stockage des actifs statiques pour les applications de petite et grande taille.

Pour utiliser le service Cloud Storage dans une application, nous pouvons utiliser les points de terminaison de l'API Storage disponibles ou en utilisant la bibliothèque cliente officielle de stockage de nœuds. Cependant, la bibliothèque cliente de stockage de nœuds ne fonctionne pas dans une fenêtre de navigateur, nous pouvons donc utiliser une fonction cloud où nous utiliserons la bibliothèque.

Un exemple de ceci est la fonction Cloud ci-dessous qui connecte et télécharge un fichier dans un Cloud Bucket créé.

const cors = require("cors")({ origin: true });
const { Storage } = require("@google-cloud/storage");
const StorageClient = new Storage();

exports.Uploader = (req, res) => {
    const { file } = req.body;
    StorageClient.bucket("TEST_BUCKET")
      .file(file.name)
      .then((response) => {
         console.log(response);
        res.status(200).send(response)
       })
      .catch((e) => res.status(422).send({error : e}));
  });
};

À partir de la fonction cloud ci-dessus, nous effectuons les deux opérations principales suivantes:

  • Tout d'abord, nous créons une connexion au Cloud Storage dans le Storage constructor et il utilise la fonctionnalité d'Application Default Credentials (ADC) sur Google Cloud pour s'authentifier auprès du Cloud Storage.

  • Deuxièmement, nous téléchargeons le fichier inclus dans le corps de la demande dans notre TEST_BUCKET en appelant le .file méthode et en passant le nom du fichier. Puisqu'il s'agit d'une opération asynchrone, nous utilisons une promesse pour savoir quand cette action a été résolue et nous envoyons un 200 réponse, mettant ainsi fin au cycle de vie de l'invocation.

Maintenant, nous pouvons étendre le Uploader Cloud Function ci-dessus pour gérer le téléchargement de l'image de profil d'un utilisateur. La fonction cloud recevra l'image de profil d'un utilisateur, la stockera dans le bucket cloud de notre application, puis mettra à jour la img_uri données dans la collection de nos utilisateurs dans le service Firestore.

require("dotenv").config();
const { Firestore } = require("@google-cloud/firestore");
const cors = require("cors")({ origin: true });
const { Storage } = require("@google-cloud/storage");

const StorageClient = new Storage();
const BucketName = process.env.STORAGE_BUCKET

exports.Uploader = (req, res) => {
  return Cors(req, res, () => {
    const { file , userId } = req.body;
    const firestore = new Firestore();
    const document = firestore.collection("users");

    StorageClient.bucket(BucketName)
      .file(file.name)
      .on("finish", () => {
        StorageClient.bucket(BucketName)
          .file(file.name)
          .makePublic()
          .then(() => {
              const img_uri = `https://storage.googleapis.com/${Bucket}/${file.path}`;
                document
                 .doc(userId)
                 .update({
                      img_uri,
                  })
                  .then((updateResult) => res.status(200).send(updateResult))
                  .catch((e) => res.status(500).send(e));
                  })
          .catch((e) => console.log(e));
      });
  });
};

Nous avons maintenant développé la fonction de téléchargement ci-dessus pour effectuer les opérations supplémentaires suivantes:

  • Tout d'abord, il établit une nouvelle connexion avec le service Firestore pour obtenir notre users collection en initialisant le constructeur Firestore et il utilise les informations d'identification par défaut de l'application (ADC) pour s'authentifier auprès du Cloud Storage.
  • Après avoir téléchargé le fichier ajouté dans le corps de la requête, nous le rendons public afin d'être accessible via une URL publique en appelant le makePublic méthode sur le fichier téléchargé. Selon le contrôle d'accès par défaut de Cloud Storage, sans rendre un fichier public, il est impossible d'accéder à un fichier sur Internet et de pouvoir le faire lors du chargement de l'application.

Remarque: Rendre un fichier public signifie que toute personne utilisant votre application peut copier le lien du fichier et avoir un accès illimité au fichier. Une façon d'éviter cela consiste à utiliser une URL signée pour accorder un accès temporaire à un fichier dans votre compartiment au lieu de le rendre entièrement public.

  • Ensuite, nous mettons à jour les données existantes de l'utilisateur pour inclure l'URL du fichier importé. Nous trouvons les données de l'utilisateur particulier à l'aide de Firestore WHERE requête et nous utilisons le userId inclus dans le corps de la requête, puis nous définissons le img_uri champ pour contenir l'URL de l'image nouvellement mise à jour.

le Upload La fonction cloud ci-dessus peut être utilisée dans toute application ayant des utilisateurs enregistrés dans le service Firestore. Tout ce qu'il faut pour faire un POST request au point de terminaison, en plaçant le SI de l'utilisateur et une image dans le corps de la requête.

Un exemple de ceci dans l'application est le UPLOAD-FILE étui qui fait un POST request à la fonction et met le lien image renvoyé par la requête dans l'état d'application.

# index.js
import Axios from 'axios'

const UPLOAD_FUNCTION = process.env.REACT_APP_UPLOAD_FUNCTION 

export const UserReducer = (state, action) => {
switch (action.type) {
 case "CREATE-USER" :
   # .....CREATE-USER-LOGIC .... 

 case "UPLOAD-FILE":
    const { file, id }  = action
    return Axios.post(UPLOAD_FUNCTION, { file, id }, {
     headers: {
         "Content-Type": "image/png",
      },
   })
  .then((response) => {})
  .catch((e) => console.log(e));

  default : 
    return console.log(`${action.type} case not recognized`)
  }
}

À partir du boîtier de commutation ci-dessus, nous faisons un POST demande à l'aide d'Axios au UPLOAD_FUNCTION en passant le fichier ajouté à inclure dans le corps de la demande et nous avons également ajouté une image Content-Type dans l'en-tête de la demande.

Après un téléchargement réussi, la réponse renvoyée par la fonction cloud contient le document de données de l'utilisateur qui a été mis à jour pour contenir une URL valide de l'image téléchargée sur le stockage cloud Google. Nous pouvons ensuite mettre à jour l'état de l'utilisateur pour contenir les nouvelles données, ce qui mettra également à jour l'image de profil de l'utilisateur src élément dans le composant de profil.

Une page de profil utilisateur qui avec une image de profil de mise à jour
Page de profil d'un utilisateur qui vient d'être mise à jour pour afficher la nouvelle image de profil mise à jour. (Grand aperçu)

Gestion des tâches Cron

Les tâches automatisées répétitives telles que l'envoi d'e-mails aux utilisateurs ou l'exécution d'une action interne à un moment donné sont la plupart du temps une fonctionnalité incluse dans les applications. Dans une application node.js standard, ces tâches peuvent être traitées comme des tâches cron à l'aide de node-cron ou node-schedule. Lors de la création d'applications sans serveur à l'aide de Google Cloud Platform, Cloud Scheduler est également conçu pour effectuer une opération cron.

Remarque: Bien que Cloud Scheduler fonctionne de la même manière que l'utilitaire cron Unix pour créer des tâches qui seront exécutées à l'avenir, il est important de noter que Cloud Scheduler n'exécute pas de commande comme le fait l'utilitaire cron. Il effectue plutôt une opération en utilisant une cible spécifiée.

Comme son nom l'indique, le Cloud Scheduler permet aux utilisateurs de planifier une opération à effectuer ultérieurement. Chaque opération est appelée un emploi et les tâches peuvent être visuellement créées, mises à jour et même détruites à partir de la section Planificateur de Cloud Console. Outre un champ de nom et de description, les tâches sur Cloud Scheduler comprennent les éléments suivants:

  • La fréquence
    Ceci est utilisé pour planifier l'exécution du travail Cron. Les planifications sont spécifiées en utilisant le format unix-cron qui est utilisé à l'origine lors de la création de travaux d'arrière-plan sur la table cron dans un environnement Linux. Le format unix-cron consiste en une chaîne de cinq valeurs représentant chacune un point temporel. Ci-dessous, nous pouvons voir chacune des cinq chaînes et les valeurs qu'elles représentent.
   - - - - - - - - - - - - - - - -   minute ( - 59 )
  |   - -  - - - - - -  - - - -  -  hour ( 0 - 23 )
  |   |   - - - - - - -  - - - - -  day of month ( 1 - 31 )
  |   |   |    - -  - - - -  - - -  month ( 1 - 12 )
  |   |   |    |     - - -  - - --  day of week ( 0 - 6 )   
  |   |   |    |    |
  |   |   |    |    |
  |   |   |    |    |
  |   |   |    |    |
  |   |   |    |    |  
  *   *   *    *    * 

L'outil générateur Crontab est pratique lorsque vous essayez de générer une valeur fréquence-temps pour un travail. Si vous avez du mal à rassembler les valeurs de temps, le générateur Crontab dispose d'une liste déroulante visuelle dans laquelle vous pouvez sélectionner les valeurs qui composent une planification et copier la valeur générée et l'utiliser comme fréquence.

  • Fuseau horaire
    Fuseau horaire à partir duquel la tâche cron est exécutée. En raison du décalage horaire entre les fuseaux horaires, les tâches cron exécutées avec différents fuseaux horaires spécifiés auront des heures d'exécution différentes.
  • Cible
    C'est ce qui est utilisé dans l'exécution du Job spécifié. Une cible pourrait être un HTTP type où la tâche envoie une demande à l'heure spécifiée à l'URL ou à un sujet Pub / Sub dans lequel la tâche peut publier des messages ou extraire des messages et enfin une application App Engine.

Le Cloud Scheduler se combine parfaitement avec les fonctions Cloud déclenchées par HTTP. Lorsqu'une tâche dans Cloud Scheduler est créée avec sa cible définie sur HTTP, cette tâche peut être utilisée pour exécuter une fonction cloud. Tout ce qui doit être fait est de spécifier le point de terminaison de la fonction cloud, de spécifier le verbe HTTP de la demande, puis d'ajouter les données à transmettre pour fonctionner dans le champ corps affiché. Comme indiqué dans l'exemple ci-dessous:

Champs requis pour créer une tâche cron à l'aide de la console cloud
Champs requis pour créer une tâche cron à l'aide de la console cloud. (Grand aperçu)

La tâche cron dans l'image ci-dessus sera exécutée à 9 heures du matin chaque jour, ce qui POST requête à l'exemple de point de terminaison d'une fonction cloud.

Un cas d'utilisation plus réaliste d'une tâche cron est l'envoi d'e-mails programmés aux utilisateurs à un intervalle donné à l'aide d'un service de messagerie externe tel que Mailgun. Pour voir cela en action, nous allons créer une nouvelle fonction cloud qui envoie un e-mail HTML à une adresse e-mail spécifiée à l'aide du package JavaScript nodemailer pour se connecter à Mailgun:

# index.js
require("dotenv").config();
const nodemailer = require("nodemailer");

exports.Emailer = (req, res) => {
  let sender = process.env.SENDER;
  const { reciever, type } = req.body

  var transport = nodemailer.createTransport({
    host: process.env.HOST,
    port: process.env.PORT,
    secure: false,
    auth: {
      user: process.env.SMTP_USERNAME,
      pass: process.env.SMTP_PASSWORD,
    },
  });

  if (!reciever) {
    res.status(400).send({ error: `Empty email address` });
  }

  transport.verify(function (error, success) {
    if (error) {
      res
        .status(401)
        .send({ error: `failed to connect with stmp. check credentials` });
    }
  });

  switch (type) {
    case "statistics":
      return transport.sendMail(
        {
          from: sender,
          to: reciever,
          subject: "Your usage satistics of demo app",
          html: { path: "./welcome.html" },
        },
        (error, info) => {
          if (error) {
            res.status(401).send({ error : error });
          }
          transport.close();
          res.status(200).send({data  : info});
        }
      );

    default:
      res.status(500).send({
        error: "An available email template type has not been matched.",
      });
  }
};

En utilisant la fonction cloud ci-dessus, nous pouvons envoyer un e-mail à l'adresse e-mail de n'importe quel utilisateur spécifiée comme valeur de destinataire dans le corps de la demande. Il effectue l'envoi d'e-mails à travers les étapes suivantes:

  • Il crée un transport SMTP pour l'envoi de messages en passant le host, user et pass qui signifie mot de passe, le tout affiché sur le tableau de bord Mailgun de l'utilisateur lors de la création d'un nouveau compte.
  • Ensuite, il vérifie si le transport SMTP dispose des informations d'identification nécessaires pour établir une connexion. S'il y a une erreur lors de l'établissement de la connexion, il met fin à l'appel de la fonction et renvoie un 401 unauthenticated code d'état.
  • Ensuite, il appelle le sendMail méthode pour envoyer l'e-mail contenant le fichier HTML comme corps de l'e-mail à l'adresse e-mail du destinataire spécifiée dans le to champ.

Remarque: Nous utilisons une instruction switch dans la fonction cloud ci-dessus pour la rendre plus réutilisable pour l'envoi de plusieurs e-mails à différents destinataires. De cette façon, nous pouvons envoyer différents e-mails en fonction du type champ inclus dans le corps de la requête lors de l'appel de cette fonction cloud.

Maintenant qu'il existe une fonction qui peut envoyer un email à un utilisateur; il ne nous reste plus qu'à créer le travail cron pour appeler cette fonction cloud. Cette fois, les tâches cron sont créées dynamiquement chaque fois qu'un nouvel utilisateur est créé à l'aide de la bibliothèque client officielle du cloud Google pour le planificateur Cloud à partir du firestoreFunction.

Nous élargissons le CREATE-USER case pour créer le travail qui envoie l'e-mail à l'utilisateur créé à un intervalle d'un jour.


require("dotenv").config();cloc
const { Firestore } = require("@google-cloud/firestore");
const scheduler = require("@google-cloud/scheduler") 
const cors = require("cors")({ origin: true });

const EMAILER = proccess.env.EMAILER_ENDPOINT
const parent = ScheduleClient.locationPath(
 process.env.PROJECT_ID,
 process.env.LOCATION_ID
);

exports.firestoreFunction = function (req, res) {
    return cors(req, res, () => {
        const { email, password, type } = req.body;
        const firestore = new Firestore();
        const document = firestore.collection("users");
        const client = new Scheduler.CloudSchedulerClient()

        if (!type) {
            res.status(422).send({ error : "An action type was not specified"});
        }

        switch (type) {
          case "CREATE-USER":

        const job = {
          httpTarget: {
            uri: process.env.EMAIL_FUNCTION_ENDPOINT,
            httpMethod: "POST",
            body: {
              email: email,
            },
          },
          schedule: "*/30 */6 */5 10 4",
          timezone: "Africa/Lagos",
          }
              if (!email || !password) {
                   res.status(422).send("email and password fields missing");
                }
            return bcrypt.genSalt(10, (err, salt) => {
              bcrypt.hash(password, salt, (err, hash) => {
                document
                  .add({
                    email: email,
                    password: hash,
                   })
                  .then((response) => {
                      client.createJob({
                          parent : parent,
                          job : job
                      }).then(() => res.status(200).send(response))
                      .catch(e => console.log(`unable to create job : ${e}`) )
                  })
                  .catch((e) =>
                      res.status(501).send(`error inserting data : ${e}`)
                    );
                  });
                });               
            default:
                res.status(422).send(`${type} is not a valid function action`)
        }
    });
};

À partir de l'extrait ci-dessus, nous pouvons voir ce qui suit:

  • Une connexion au Cloud Scheduler à partir du constructeur Scheduler à l'aide des informations d'identification par défaut de l'application (ADC) est établie.
  • Nous créons un objet composé des détails suivants qui composent le travail cron à créer:
    • uri
      Le point de terminaison de notre fonction cloud de messagerie dans lequel une demande serait adressée.
    • body
      Il s'agit des données contenant l'adresse e-mail de l'utilisateur à inclure lors de la demande.
    • schedule
      Le format cron unix représentant l'heure à laquelle cette tâche cron doit être effectuée.
  • Une fois que la promesse d'insérer le document de données de l'utilisateur est résolue, nous créons le travail cron en appelant le createJob méthode et en passant l'objet de travail et le parent.
  • L'exécution de la fonction se termine par un 200 code de statut après la promesse du createJob l'opération a été résolue.

Une fois la tâche créée, nous la verrons répertoriée sur la page du planificateur.

Liste de toutes les tâches cron planifiées, y compris la dernière tâche créée.
Liste de toutes les tâches cron planifiées, y compris la dernière tâche créée. (Grand aperçu)

Sur l'image ci-dessus, nous pouvons voir l'heure prévue pour l'exécution de ce travail. Nous pouvons décider d'exécuter manuellement ce travail ou d'attendre qu'il soit exécuté à l'heure planifiée.

Conclusion

Dans cet article, nous avons examiné les applications sans serveur et les avantages de leur utilisation. Nous avons également examiné de manière approfondie comment les développeurs peuvent gérer leurs applications sans serveur sur Google Cloud à l'aide de Cloud Functions afin que vous sachiez maintenant comment Google Cloud prend en charge l'utilisation d'applications sans serveur.

Dans les années à venir, nous verrons certainement un grand nombre de développeurs s'adapter à l'utilisation d'applications sans serveur lors de la construction d'applications. Si vous utilisez des fonctions cloud dans un environnement de production, il est recommandé de lire cet article d'un avocat de Google Cloud sur «6 stratégies pour faire évoluer vos applications sans serveur».

Le code source des fonctions cloud créées est disponible dans ce référentiel Github ainsi que dans l'application frontale utilisée dans ce référentiel Github. L'application frontale a été déployée à l'aide de Netlify et peut être testée en direct ici.

Références

Éditorial fracassant(ks, ra, yk, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *