Des sites statiques aux applications JAMstack des utilisateurs finaux avec FaunaDB
À propos de l'auteur
Bryan est un concepteur, développeur et éducateur passionné de CSS et de sites statiques. Il travaille activement pour encadrer et enseigner aux développeurs et concepteurs la valeur… En savoir plus sur Bryan
Robinson …
Pour passer du «site» à l'application, nous devons plonger dans le monde du contenu «généré par l'application». Dans cet article, nous allons commencer dans ce monde avec la puissance des données sans serveur. Nous commencerons par une démonstration simple en ingérant et en publiant des données sur FaunaDB puis nous étendrons cette fonctionnalité dans une application à part entière en utilisant Auth0, le système de jetons de FaunaDB et les fonctions définies par l'utilisateur.
s'est avéré être l'un des meilleurs moyens de produire des sites axés sur le contenu, mais c'est également un excellent endroit pour héberger des applications. Si vous avez utilisé JAMstack pour vos sites Web performants, les démos de cet article vous aideront également à étendre ces philosophies aux applications.
Lorsque vous utilisez JAMstack pour créer des applications, vous avez besoin d'un service de données qui s'intègre le plus aspects importants de la philosophie JAMstack:
Distribution mondiale
Zéro besoin opérationnel
Une API conviviale pour les développeurs.
Dans l'écosystème JAMstack, il existe de nombreuses sociétés de logiciels en tant que service qui offrent des moyens de obtenir et stocker des types de données spécifiques. Que vous souhaitiez envoyer des e-mails, des SMS ou passer des appels téléphoniques (Twilio) ou accepter des soumissions de formulaires de manière efficace (Formspree, Formingo, Formstack, etc.), il semble qu'il existe une API pour presque tout.
Ce sont d'excellents services qui peuvent faire une grande partie du travail de bas niveau de nombreuses applications, mais une fois que vos données sont plus complexes qu'une feuille de calcul ou doivent être mises à jour et stockées en temps réel, il est peut-être temps de consulter une base de données.
L'API de service peut encore être utilisé, mais une base de données centrale gérant l'état et les opérations de votre application devient beaucoup plus importante. Même si vous avez besoin d'une base de données, vous voulez toujours qu'elle suive les principales philosophies JAMstack que nous avons décrites ci-dessus. Cela signifie que nous ne voulons pas héberger notre propre serveur de base de données. Nous avons besoin d'une solution de base de données en tant que service. Notre base de données doit être optimisée pour JAMstack:
Optimisée pour les appels d'API à partir d'un navigateur ou d'un processus de construction.
Flexible pour modéliser vos données de la manière spécifique dont votre application a besoin.
Distribution mondiale de nos données comme un CDN héberge nos sites.
Évolutivité mains libres sans intervention d'un administrateur de base de données ou d'un développeur.
Le service que vous recherchez doit suivre ces principes de données sans serveur. Dans nos démos, nous explorerons FaunaDB une base de données mondiale sans serveur, avec GraphQL natif pour assurer que nous gardons nos applications en phase avec les philosophies de JAMstack.
Plongeons-nous dans le code! [19659018] Une application de livre d'or JAMstack avec Gatsby et la faune
Je suis un grand fan de la réinvention des outils et concepts Internet des années 1990 et du début des années 2000. Nous pouvons prendre ces concepts et les faire sentir frais avec le nouvel ensemble d'outils et d'interactions.
Un aperçu de l'application que nous créons. Un formulaire de signature avec une liste de signatures ci-dessous. Le formulaire remplira une base de données FaunaDB et cette base de données créera la liste des vues. ( Grand aperçu )
Dans cette démo, nous allons créer une application qui faisait fureur à cette époque: le livre d'or. Un livre d'or n'est rien d'autre qu'un contenu et une interaction générés par l'application. Un utilisateur peut venir sur le site, voir toutes les signatures des anciens «invités», puis laisser les leurs.
Pour commencer, nous rendrons statiquement notre site et construirons nos données à partir de Fauna pendant notre étape de construction. Cela fournira les performances rapides que nous attendons d'un site JAMstack. Pour ce faire, nous utiliserons GatsbyJS.
Configuration initiale
Notre première étape sera d'installer Gatsby globalement sur notre ordinateur. Si vous n'avez jamais passé beaucoup de temps sur la ligne de commande, le didacticiel «partie 0» de Gatsby vous aidera à être opérationnel. Si Node et NPM sont déjà installés, vous installerez Gatsby CLI globalement et créerez un nouveau site avec lui à l'aide des commandes suivantes:
npm install -g gatsby-cli
gatsby new
Gatsby est livré avec un grand référentiel de démarreurs qui peut vous aider à démarrer votre projet. Pour cette démo, j'ai choisi un simple démarreur équipé du framework Bulma CSS.
gatsby new guestbook-app https://github.com/amandeepmittal/gatsby-bulma-quickstart[19659030diplomatedCelanousdonneunbondépartpointetstructureIlprésenteégalementl'avantagesupplémentairedeproposerdesstylesprêtsàl'emploi
Faisons un peu de nettoyage pour les choses dont nous n'avons pas besoin. Nous allons commencer par simplifier notre components.header.js
importation de React à partir de 'react';
import './style.scss';
const Header = ({siteTitle}) => (
Signez notre livre d'or virtuel
Si vous aimez tout ce que nous faisons, assurez-vous de signer notre livre d'or virtuel
);
exporter l'en-tête par défaut;
Cela supprimera une grande partie du contenu de marque. N'hésitez pas à personnaliser cette section, mais nous n'écrirons aucun de nos codes ici.
Ensuite, nous allons nettoyer le fichier components / midsection.js . C'est là que le code de notre application sera rendu.
importez React, {useState} de 'react';
importer des signatures à partir de './signatures';
importer SignForm à partir de './sign-form';
const Midsection = () => {
const [sigData, setSigData] = useState (data.allSignatures.nodes);
revenir (
Signer ici
Afficher les signatures
)
}
exporter la section médiane par défaut;
Dans ce code, nous avons principalement supprimé le contenu "site" et ajouté quelques nouveaux composants. Un qui contiendra notre formulaire pour soumettre une signature et un composant pour contenir la liste des signatures.
Maintenant que nous avons une liste relativement vierge, nous pouvons configurer notre base de données FaunaDB.
Up A FaunaDB Collection
Après vous être connecté à Fauna (ou ouvrir un compte), vous aurez la possibilité de créer une nouvelle base de données. Nous allons créer une nouvelle base de données appelée livre d'or .
L'état initial de notre collection de signatures après l'ajout de notre premier document. ( Grand aperçu )
Dans cette base de données, nous allons créer une "Collection" appelée signature . Collections dans Fauna un groupe de documents qui sont à leur tour des objets JSON.
Dans cette nouvelle collection, nous allons créer un nouveau document avec le JSON suivant:
{
nom: "Bryan Robinson",
message:
"Lorem ipsum dolor amet somme Lorem ipsum dolor amet somme Lorem ipsum dolor amet somme Lorem ipsum dolor amet somme"
}
Ce sera le schéma de données simple pour chacune de nos signatures. Pour chacun de ces documents, Fauna créera des données supplémentaires autour de lui.
{
"ref": Ref (Collection ("signatures"), "262884172900598291"),
"ts": 1586964733980000,
"Les données": {
"nom": "Bryan Robinson",
"message": "Lorem ipsum dolor amet somme Lorem ipsum dolor amet somme Lorem ipsum dolor amet somme Lorem ipsum dolor amet somme"
}
}
La référence est l'identifiant unique à l'intérieur de Fauna et la ts est l'heure (en tant qu'horodatage Unix) du document a été créé / mis à jour.
Après avoir créé notre données, nous voulons un moyen facile de saisir toutes ces données et de les utiliser dans notre site. Dans Fauna, le moyen le plus efficace pour obtenir des données est via un index. Nous allons créer un index appelé allSignatures . Cela va récupérer et retourner tous nos documents de signature dans la collection.
Maintenant que nous avons un moyen efficace d'accéder aux données dans Gatsby, nous avons besoin de Gatsby pour savoir où les obtenir.
Configuration du plug-in de source de données Fauna Gatsby
npm install gatsby-source-faunadb
Après avoir installé ce plugin sur notre site Web, Gatsby possède un référentiel de plug-ins qui peuvent récupérer des données à partir de diverses sources. projet, nous devons le configurer dans notre fichier gatsby-config.js . Dans le tableau plugins de notre projet, nous allons ajouter un nouvel élément.
{
résoudre: `gatsby-source-faunadb`,
options: {
// Le secret de la clé que vous utilisez pour vous connecter à votre base de données Fauna.
// Vous pouvez en générer sur l'onglet "Sécurité" de votre console Fauna.
secret: process.env.YOUR_FAUNADB_SECRET,
// Le nom de l'index que vous souhaitez interroger
// Vous pouvez créer un index dans l'onglet "Index" de votre console Fauna.
index: `allSignatures`,
// C'est le nom sous lequel vos données apparaîtront dans les requêtes Gatsby GraphQL
// Ce qui suit créera des requêtes appelées `allBird` et` bird`.
type: "Signatures",
// Si vous devez limiter le nombre de documents retournés, vous pouvez spécifier un
// Nombre maximum facultatif à lire.
// taille: 100
},
},
Dans cette configuration, vous lui fournissez votre clé secrète de faune, le nom d'index que nous avons créé et le «type» auquel nous voulons accéder dans notre requête Gatsby GraphQL.
Où est-ce que process.env.YOUR_FAUNADB_SECRET
Dans votre projet, créez un fichier .env - et incluez ce fichier dans votre .gitignore! Ce fichier donnera à la configuration Webpack de Gatsby la valeur secrète. Cela gardera vos informations sensibles en sécurité et non stockées dans GitHub.
YOUR_FAUNADB_SECRET = "valeur de la faune"
Nous pouvons ensuite nous diriger vers l'onglet "Sécurité" de notre base de données et créer une nouvelle clé. Comme il s'agit d'un secret protégé, il est sûr d'utiliser un rôle de «serveur». Lorsque vous enregistrez la clé, elle vous fournira votre secret. Assurez-vous de saisir cela maintenant, car vous ne pouvez pas l'obtenir à nouveau (sans recréer la clé).
Une fois la configuration établie, nous pouvons écrire une requête GraphQL dans nos composants pour récupérer les données à la construction
Obtention des données et création du modèle
Nous allons ajouter cette requête à notre composant Midsection pour la rendre accessible à nos deux composants.
const Midsection = () => {
const data = useStaticQuery (
graphql`
requête GetSignatures {
allSignatures {
nœuds {
Nom
message
_ts
_id
}
}
} `
);
// ... reste du composant
}
Ceci accède au type Signatures que nous avons créé dans la configuration. Il saisira toutes les signatures et fournira un tableau de nœuds. Ces nœuds contiendront les données dont nous avons besoin: nom message ts id .
Nous allons définir ces données dans notre état - cela facilitera leur mise à jour plus tard.
Maintenant, nous pouvons passer sigData comme accessoire dans et setSigData dans .
Configurons notre composant Signatures pour utiliser ces données!
importez React depuis 'react';
importer la signature à partir de './signature'
const Signatures = (props) => {
const SignatureMarkup = () => {
return props.sigData.map ((signature, index) => {
revenir (
)
}).inverser()
}
revenir (
)
}
exporter les signatures par défaut
Dans cette fonction, nous allons .map () sur nos données de signature et créer un tableau de balisage basé sur un nouveau composant dans lequel nous transmettons les données.
Le Le composant Signature gérera le formatage de nos données et le renvoi d'un ensemble approprié de code HTML.
importez React de 'react';
const Signature = ({signature}) => {
const dateObj = nouvelle date (signature._ts / 1000);
let dateString = `$ {dateObj.toLocaleString ('default', {semaine: 'long'})}, $ {dateObj.toLocaleString ('default', {mois: 'long'})} $ {dateObj.getDate () } à $ {dateObj.toLocaleTimeString ('défaut', {heure: '2 chiffres', minute: '2 chiffres', heure12: faux})} `
revenir (
{signature.name} - {dateString}
{signature.message}
)};
exporter la signature par défaut;
À ce stade, si vous démarrez votre serveur de développement Gatsby, vous devriez avoir une liste de signatures existant actuellement dans votre base de données. Exécutez la commande suivante pour être opérationnel:
gatsby develop
Toute signature stockée dans notre base de données créera du HTML dans ce composant. Mais comment pouvons-nous obtenir des signatures dans notre base de données?
Configurons un composant de formulaire de signature pour envoyer des données et mettre à jour notre liste de signatures.
Faisons en sorte que notre JAMstack Guestbook soit interactif
Premièrement, nous allons configurer la base structure pour notre composant. Il affichera un formulaire simple sur la page avec une entrée de texte, une zone de texte et un bouton pour la soumission.
import React from 'react';
import faunadb, {requête as q} from "faunadb"
var client = new faunadb.Client ({secret: process.env.GATSBY_FAUNA_CLIENT_SECRET})
exporter la classe par défaut SignForm étend React.Component {
constructeur (accessoires) {
super (accessoires)
this.state = {
sigName: "",
sigMessage: ""
}
}
handleSubmit = async event => {
// Gérer la soumission
}
handleInputChange = event => {
// Lorsqu'une entrée change, mettez à jour l'état
}
render () {
revenir (
)
}
}
Pour commencer, nous allons configurer notre état pour inclure le nom et le message. Nous les remplacerons par défaut par des chaînes vides et les insérerons dans nos et .
Lorsqu'un utilisateur modifie la valeur de l'un de ces champs, nous utilisons la méthode handleInputChange . Lorsqu'un utilisateur soumet le formulaire, nous utilisons la méthode handleSubmit .
Le changement d'entrée acceptera l'événement. À partir de cet événement, il obtiendra la valeur et le nom de la cible actuelle. Nous pouvons ensuite modifier l'état des propriétés de notre objet d'état - sigName, sigMessage ou toute autre chose.
Une fois que l'état a changé, nous pouvons utiliser l'état dans notre méthode handleSubmit .
Cette fonction appellera une nouvelle méthode createSignature () . Ceci se connectera à Fauna pour créer un nouveau document à partir de nos éléments d'état.
La méthode addSignature () mettra à jour nos données de liste de signatures avec la réponse que nous recevons de Fauna.
Afin de écrire dans notre base de données, nous devrons configurer une nouvelle clé dans Fauna avec des autorisations minimales. Notre clé de serveur bénéficie d'autorisations plus élevées, car elle n'est utilisée que pendant la génération et ne sera pas visible dans notre source.
Cette clé doit uniquement autoriser la possibilité de créer uniquement de nouveaux éléments dans notre collection de signatures . .
Remarque : Un utilisateur peut toujours être malveillant avec cette clé, mais il ne peut faire autant de dégâts qu'un bot soumettant ce formulaire, c'est donc un compromis que je souhaite à faire pour cette application.
Un regard sur le panneau de sécurité FaunaDB. Dans cette photo, nous créons un rôle "client" qui n'autorise que l'autorisation "Créer" pour ces clés API. ( Grand aperçu )
Pour cela, nous allons créer un nouveau "Rôle" dans l'onglet "Sécurité" de notre tableau de bord. Nous pouvons ajouter des autorisations sur une ou plusieurs de nos collections. Dans cette démo, nous n'avons besoin que de signatures et nous pouvons sélectionner la fonctionnalité "Créer".
Après cela, nous générons une nouvelle clé qui utilise ce rôle.
Pour utiliser cette clé, nous ' ll instancier une nouvelle version du SDK JavaScript Fauna. Ceci est une dépendance du plugin Gatsby que nous avons installé, nous y avons donc déjà accès.
import faunadb, {query as q} from "faunadb"
var client = new faunadb.Client ({secret: process.env.GATSBY_FAUNA_CLIENT_SECRET})
En utilisant une variable d'environnement préfixée par GATSBY_ nous y avons accès dans notre navigateur JavaScript (assurez-vous d'ajouter dans votre fichier .env ).
En important l'objet query depuis le SDK, nous avons accès à toutes les méthodes disponibles dans le langage de requête de Fauna de Fauna ( FQL). Dans ce cas, nous voulons utiliser la méthode Create pour créer un nouveau document sur notre collection.
Nous passons la fonction Create à la méthode client.query () . Créer prend une référence de collection et un objet d'information à transmettre à un nouveau document. Dans ce cas, nous utilisons q.Collection et une chaîne du nom de notre collection pour obtenir la référence à la collection. Le deuxième argument concerne nos données. Vous pouvez passer d'autres éléments dans l'objet, nous devons donc dire à Fauna que nous lui envoyons spécifiquement la propriété data sur cet objet.
Ensuite, nous lui transmettons le nom et le message que nous avons collectés dans notre état. La réponse que nous recevons de Fauna est tout l'objet de notre Document. Cela inclut nos données dans un objet data ainsi qu'un identifiant de faune et un horodatage. Nous reformatons ces données de manière à ce que notre liste de signatures puisse les utiliser et les renvoyons à notre fonction handleSubmit .
Notre gestionnaire de soumission transmettra ensuite ces données à notre setSigData prop qui notifiera notre composant Signatures pour effectuer un nouveau rendu avec ces nouvelles données. Cela permet à notre utilisateur de savoir immédiatement que sa soumission a été acceptée.
Reconstruction du site
Tout fonctionne dans le navigateur, mais les données n'ont pas encore été mises à jour dans notre application statique.
À partir d'ici, nous devons dire à notre hôte JAMstack de reconstruire notre site. Beaucoup ont la possibilité de spécifier un webhook pour déclencher un déploiement. Puisque j'héberge cette démo sur Netlify, je peux créer un nouveau "Déployer le webhook" dans leur administrateur et créer une nouvelle fonction triggerBuild . Cette fonction utilisera la méthode native JavaScript fetch () et enverra une demande de publication à cette URL. Netlify reconstruira ensuite l'application et récupérera les dernières signatures.
Gatsby Cloud et Netlify ont mis en œuvre des méthodes de gestion des constructions «incrémentielles» avec Gatsby, ce qui accélère considérablement les temps de construction. Ce type de construction peut se produire très rapidement maintenant et se sentir presque aussi vite qu'un site rendu par un serveur traditionnel.
Chaque signature qui est ajoutée obtient un retour rapide à l'utilisateur qu'elle a été soumise, est perpétuellement stockée dans une base de données, et a servi de code HTML via un processus de génération.
Vous vous sentez toujours un peu trop comme un site Web typique? Prenons tous ces concepts un peu plus loin.
Créer une application Mindful avec Auth0, Identité de la faune et fonctions définies par l'utilisateur de la faune (UDF)
Être attentif est une compétence importante à cultiver. Qu'il s'agisse de penser à vos relations, à votre carrière, à votre famille ou simplement à vous promener dans la nature, il est important d'être attentif aux personnes et aux endroits qui vous entourent.
Un coup d'œil à l'écran final de l'application montrant une «Mission consciente», «Missions passées» et un bouton «Déconnexion». ( Grand aperçu )
Cette application a pour but de vous aider à vous concentrer sur une idée aléatoire chaque jour et à passer en revue les différentes idées des derniers jours.
Pour ce faire, nous devons introduire un élément clé pour la plupart des applications: authentification. Avec l'authentification, vient des problèmes de sécurité supplémentaires. Bien que ces données ne soient pas particulièrement sensibles, vous ne voulez pas qu'un utilisateur accède à l'historique d'un autre utilisateur.
Étant donné que nous étendrons les données à un utilisateur spécifique, nous ne voulons pas non plus stocker de secret. clés sur le code du navigateur, car cela ouvrirait d'autres failles de sécurité.
Nous pourrions créer un flux d'authentification complet en utilisant rien d'autre que notre intelligence et une base de données utilisateur avec Fauna. Cela peut sembler intimidant et nous éloigne des fonctionnalités que nous voulons écrire. La grande chose est qu'il y a certainement une API pour cela dans JAMstack! Dans cette démo, nous allons explorer l'intégration d'Auth0 avec Fauna. Nous pouvons utiliser l'intégration de plusieurs façons.
Configuration d'Auth0 pour se connecter à Fauna
De nombreuses implémentations d'authentification avec JAMstack reposent fortement sur des fonctions sans serveur. Cela déplace une grande partie des problèmes de sécurité d'une entreprise axée sur la sécurité comme Auth0 vers le développeur individuel.
Diagramme décrivant la méthode compliquée d'utilisation d'une fonction sans serveur pour gérer l'authentification et la génération de jetons. ( Grand aperçu )
Le flux typique serait d'envoyer une demande de connexion à une fonction sans serveur. Cette fonction demanderait un utilisateur à Auth0. Auth0 fournirait le jeton Web JSON (JWT) de l'utilisateur et la fonction fournirait toute information supplémentaire sur l'utilisateur dont notre application a besoin. La fonction regrouperait alors tout et l'enverrait au navigateur.
Il y a beaucoup d'endroits dans ce flux d'authentification où un développeur pourrait introduire une faille de sécurité.
Au lieu de cela, demandons à Auth0 de tout regrouper pour nous à l'intérieur du JWT qu'il envoie.
Un diagramme décrivant l'authentification rationalisée et le flux de génération de jetons lors de l'utilisation du système de règles d'Auth0. ( Grand aperçu )
Nous le ferons en utilisant la fonctionnalité de règles d'Auth0 pour demander à Fauna un jeton utilisateur à encoder dans notre JWT. Cela signifie que contrairement à notre livre d'or, nous n'aurons aucune clé Fauna dans notre code frontal. Tout sera géré en mémoire à partir de ce jeton JWT.
Configuration de l'application Auth0 et de la règle
Tout d'abord, nous devons configurer les bases de notre application Auth0.
Après les étapes de configuration dans leur procédure pas à pas de base obtient les informations de base importantes remplies. Assurez-vous de remplir le port localhost approprié pour votre fournisseur de choix comme l'un de vos domaines autorisés.
Une fois les bases de l'application configurées, nous ' Je vais dans la section "Règles" de notre compte.
Cliquez sur "Créer une règle" et sélectionnez "Règle vide" (ou commencez à partir de l'un de leurs nombreux modèles qui sont des points de départ utiles).
Nous donnons à la règle une fonction qui prend l'utilisateur, le contexte et un rappel depuis Auth0. Nous devons configurer et récupérer un jeton de serveur pour initialiser notre SDK JavaScript Fauna et initialiser notre client. Tout comme dans notre livre d'or, nous allons créer une nouvelle base de données et gérer nos jetons en «sécurité».
À partir de là, nous voulons envoyer une requête à Fauna pour créer ou connecter notre utilisateur. Pour garder notre code de règle simple (et le rendre réutilisable), nous allons écrire notre première «fonction définie par l'utilisateur» (UDF) pour Fauna. Un UDF est une fonction écrite en FQL qui s'exécute sur l'infrastructure de Fauna.
Premièrement, nous allons créer une collection pour nos utilisateurs. Vous n'avez pas besoin de créer un premier document ici, car ils seront créés en arrière-plan par notre règle Auth0 chaque fois qu'un nouvel utilisateur Auth0 est créé.
Ensuite, nous avons besoin d'un index pour rechercher nos utilisateurs Collection basée sur l'adresse e-mail. Cet index est plus simple que notre livre d'or, nous pouvons donc l'ajouter au tableau de bord. Nommez l'index user_by_email définissez la collection sur users et les termes sur data.email . Cela nous permettra de transmettre une adresse e-mail à l'index et de récupérer un document utilisateur correspondant.
Il est temps de créer notre FDU. Dans le tableau de bord, accédez à «Fonctions» et créez-en une nouvelle nommée user_login_or_create .
Requête (
Lambda (
["userEmail", "userObj"]// Arguments
Laisser(
{user: Match (Index ("user_by_email"), Var ("userEmail"))}, // Définir la variable utilisateur
Si(
Existe (Var ("utilisateur")), // Vérifier si l'utilisateur existe
Create (Tokens (null), {instance: Select ("ref", Get (Var ("user")))}), // Renvoie un jeton pour cet élément dans la collection des utilisateurs (en d'autres termes, l'utilisateur)
Let (// Else: définir une variable
{
newUser: Create (Collection ("users"), {data: Var ("userObj")}), // Créez un nouvel utilisateur et obtenez sa référence
token: Create (Tokens (null), {// Créez un token pour cet utilisateur
instance: Select ("ref", Var ("newUser"))
})
},
Var ("token") // retourne le token
)
)
)
)
)
Notre UDF acceptera une adresse e-mail utilisateur et le reste des informations utilisateur. Si un utilisateur existe dans une collection d'utilisateurs il créera un jeton pour l'utilisateur et le renverra. Si un utilisateur n'existe pas, il créera ce document utilisateur puis enverra un jeton à notre règle Auth0.
Nous pouvons ensuite stocker le jeton sous la forme d'un idToken attaché au contexte dans notre JWT. Le jeton a besoin d'une URL comme clé. Comme il s'agit d'un jeton Faune, nous pouvons utiliser une URL Faune. Quoi qu'il en soit, vous l'utiliserez pour y accéder dans votre code.
Ce jeton ne dispose pas encore d'autorisations. Nous devons entrer dans nos règles de sécurité et configurer un nouveau rôle.
Nous allons créer un rôle "AuthedUser". Nous n'avons pas encore besoin d'ajouter d'autorisations, mais au fur et à mesure que nous créons de nouveaux UDF et de nouvelles collections, nous mettrons à jour les autorisations ici. Au lieu de générer une nouvelle clé pour utiliser ce rôle, nous souhaitons ajouter aux «adhésions» de ce rôle. Sur l'écran Adhésions, vous pouvez sélectionner une collection à ajouter en tant que membre. Les documents de cette collection (dans notre cas, nos utilisateurs), auront les autorisations définies sur ce rôle données via leur Token.
Maintenant, lorsqu'un utilisateur se connecte via Auth0, il lui sera retourné un Token qui correspond à son Document utilisateur et dispose de ses autorisations.
D'ici, nous revenons à notre application.
Implémentez la logique pour quand l'utilisateur est connecté
Écran de connexion / inscription Auth0 par défaut. Tout le flux de connexion peut être contenu dans les écrans Auth0. ( Grand aperçu )
D'abord, nous aurons besoin du SDK Auth0 SPA.
npm install @ auth0 / auth0-spa-js
import create createAuth0Client de '@ auth0 / auth0-spa -js ';
importer {changeToHome} à partir de './layouts/home'; // Disposition de la maison
importer {changeToMission} à partir de './layouts/myMind'; // Présentation actuelle de la mission de pleine conscience
laissez auth0 = null;
var currentUser = null;
const configureClient = async () => {
// Configure le SDK Auth0
auth0 = attendre createAuth0Client ({
domaine: "mindfulness.auth0.com",
client_id: "32i3ylPhup47PYKUtZGRnLNsGVLks3M6"
});
};
const checkUser = async () => {
// retourne les informations utilisateur de n'importe quelle méthode
const isAuthenticated = attendre auth0.isAuthenticated ();
if (isAuthenticated) {
renvoyer attendre auth0.getUser ();
}
}
const loadAuth = async () => {
// Charge et vérifie l'auth
attendre configureClient ();
const isAuthenticated = attendre auth0.isAuthenticated ();
if (isAuthenticated) {
// affiche le contenu fermé
currentUser = attendre auth0.getUser ();
changeToMission (); // Afficher l'écran "Aujourd'hui"
revenir;
} autre {
changeToHome (); // Afficher la "page d'accueil" déconnectée
}
const query = window.location.search;
if (query.includes ("code =") && query.includes ("state =")) {
// Traite l'état de connexion
attendre auth0.handleRedirectCallback ();
currentUser = attendre auth0.getUser ();
changeToMission ();
// Utilisez replaceState pour rediriger l'utilisateur et supprimer les paramètres de chaîne de requête
window.history.replaceState ({}, document.title, "/");
}
}
const login = async () => {
attendre auth0.loginWithRedirect ({
redirect_uri: window.location.origin
});
}
const logout = async () => {
auth0.logout ({
returnTo: window.location.origin
});
window.localStorage.removeItem ('currentMindfulItem')
changeToHome (); // Retour à l'état déconnecté
}
export {auth0, loadAuth, currentUser, checkUser, login, logout}
Premièrement, nous configurons le SDK avec notre client_id d'Auth0. Ce sont des informations sûres à stocker dans notre code.
Ensuite, nous configurons une fonction qui peut être exportée et utilisée dans plusieurs fichiers pour vérifier si un utilisateur est connecté. La bibliothèque Auth0 fournit un isAuthenticated () . Si l'utilisateur est authentifié, nous pouvons renvoyer les données utilisateur avec auth0.getUser () .
Nous avons configuré un login () et logout () ] et une fonction loadAuth () pour gérer le retour d'Auth0 et changer l'état de notre interface utilisateur à l'écran "Mission" avec l'idée Mindful d'aujourd'hui.
Une fois que tout est configuré, nous avons
Nous allons créer une nouvelle fonction pour que nos fonctions de faune se référencent pour obtenir la configuration de jeton appropriée.
const AUTH_PROP_KEY = "https://faunad.com/id/secret ";
var faunadb = require ('faunadb'),
q = faunadb.query;
fonction asynchrone getUserClient (currentUser) {
renvoie un nouveau faunadb.Client ({secret: currentUser [AUTH_PROP_KEY]})
}
Cela renvoie une nouvelle connexion à Fauna en utilisant notre Token d'Auth0. Ce jeton fonctionne de la même manière que les clés des exemples précédents.
Générez un sujet Mindful aléatoire et stockez-le dans Fauna
Pour commencer, nous avons besoin d'une collection d'articles pour stocker notre liste d'objets Mindful. Nous allons créer une collection appelée «choses conscientes» et créer un certain nombre d'éléments avec le schéma suivant:
{
"title": "Carrière",
"description": "Pensez aux prochaines étapes que vous voulez faire dans votre carrière. Quelle est la prochaine étape facilement réalisable que vous pouvez faire?",
"color": "# C6D4FF",
"textColor": "noir"
}
À partir d'ici, nous allons passer à notre JavaScript et créer une fonction pour ajouter et renvoyer un élément aléatoire de cette collection.
Pour commencer, nous allons instancier notre client avec notre méthode getUserClient () .
De là, nous allons récupérer tous les documents de notre collection mindful_things . Paginate () prend par défaut 64 éléments par page, ce qui est plus que suffisant pour nos données. Nous allons récupérer un élément aléatoire dans le tableau qui est revenu de la faune. Ce sera ce que la faune appelle un «Ref». Une référence est une référence complète à un document que les différentes fonctions FQL peuvent utiliser pour localiser un document.
Nous transmettrons cette référence à un nouvel UDF qui gérera le stockage d'un nouvel objet horodaté pour cet utilisateur stocké dans un nouveau user_things Collection.
Nous créerons la nouvelle collection, mais nous demanderons à notre UDF de lui fournir les données lors de son appel.
Nous créerons une nouvelle UDF dans le tableau de bord Fauna avec le nom addUserMindful qui acceptera cette référence aléatoire.
Comme avec notre UDF de connexion auparavant, nous utiliserons la méthode Lambda () FQL qui prend un tableau d'arguments. [19659005] Sans transmettre aucune information utilisateur à la fonction, FQL est en mesure d'obtenir notre référence utilisateur en appelant simplement la fonction Identity () . Tout ce que nous avons de notre randomRef est la référence à notre document. Nous allons exécuter un Get () pour obtenir l'objet complet. Nous allons créer Create () un nouveau document dans la collection user_things avec notre référence utilisateur et nos informations aléatoires.
Nous retournons ensuite l'objet creation creation sortir de notre Lambda. Nous retournons ensuite à notre JavaScript et renvoyons l'objet de données avec la clé mindful à l'endroit où cette fonction est appelée.
Rendre notre objet Mindful sur la page
Lorsque notre utilisateur est authentifié, vous souvenez-vous qu'il a appelé une méthode changeToMission () . Cette fonction fait basculer les éléments de la page de l'écran «Accueil» vers un balisage pouvant être rempli par nos données. Une fois qu'elle a été ajoutée à la page, la fonction renderToday () est appelée pour ajouter du contenu à l'aide de quelques règles.
La première règle de Serverless Data Club n'est pas de faire des requêtes HTTP à moins que vous n'ayez à le faire. En d'autres termes, cachez quand vous le pouvez. Que ce soit pour créer une application complète à l'échelle PWA avec Service Workers ou simplement mettre en cache la réponse de votre base de données avec localStorage, mettre en cache les données et extraire uniquement lorsque cela est nécessaire.
La première règle de notre conditionnel est de vérifier localStorage. Si localStorage contient un currentMindfulItem alors nous devons vérifier sa date pour voir si elle date d'aujourd'hui. If it is, we’ll render that and make no new requests.
The second rule of Serverless Data Club is to make as few requests as possible without the responses of those requests being too large. Dans cette veine, notre deuxième règle conditionnelle consiste à vérifier le dernier élément de l'utilisateur actuel et à voir s'il date d'aujourd'hui. If it is, we’ll store it in localStorage for later and then render the results.
Finally, if none of these are true, we’ll fire our getRandomMindfulFromFauna() function, format the result, store that in localStorage, and then render the result.
Get the latest item from a user
I glossed over it in the last section, but we also need some functionality to retrieve the latest mindful object from Fauna for our specific user. In our getLatestFromFauna() method, we’ll again instantiate our Fauna client and then call a new UDF.
Our new UDF is going to call a Fauna Index. Un index est un moyen efficace d'effectuer une recherche dans une base de données Fauna. In our case, we want to return all user_things by the user field. Then we can also sort the result by timestamp and reverse the default ordering of the data to show the latest first.
Simple Indexes can be created in the Index dashboard. Since we want to do the reverse sort, we’ll need to enter some custom FQL into the Fauna Shell (you can do this in the database dashboard Shell section).
This creates an Index named getMindfulByUserReversecreated from our user_thing Collection. The terms object is a list of fields to search by. In our case, this is just the user field on the data object. We then provide values to return. In our case, we need the Ref and the Timestamp and we’ll use the reverse property to reverse order our results by this field.
We’ll create a new UDF to use this Index.
Query(
Lambda(
[],
If( // Check if there is at least 1 in the index
GT(
Count(
Select(
"data",
Paginate(Match(Index("getMindfulByUserReverse"), Identity()))
)
),
0
),
Let( // if more than 0
{
match: Paginate(
Match(Index("getMindfulByUserReverse"), Identity()) // Search the index by our User
),
latestObj: Take(1, Var("match")), // Grab the first item from our match
latestRef: Select(
["data"],
Get(Select(["data", 0, 1]Var("latestObj"))) // Get the data object from the item
),
latestTime: Select(["data", 0, 0]Var("latestObj")), // Get the time
merged: Merge( // merge those items into one object to return
{ latestTime: Var("latestTime") },
{ latestMindful: Var("latestRef") }
)
},
Var("merged")
),
Let({ error: { err: "No data" } }, Var("error")) // if there aren't any, return an error.
)
)
)
This time our Lambda() function doesn’t need any arguments since we’ll have our User based on the Token used.
First, we’ll check to see if there’s at least 1 item in our Index. If there is, we’ll grab the first item’s data and time and return that back as a merged object.
After we get the latest from Fauna in our JavaScript, we’ll format it to a structure our storeCurrent() and render() methods expect it and return that object.
Now, we have an application that creates, stores, and fetches data for a daily message to contemplate. Un utilisateur peut l'utiliser sur son téléphone, sur sa tablette, sur l'ordinateur et tout synchroniser. We could turn this into a PWA or even a native app with a system like Ionic.
We’re still missing one feature. Affichage d'un certain nombre d'éléments passés. Since we’ve stored this in our database, we can retrieve them in whatever way we need to.
Pull the latest X Mindful Missions to get a picture of what you’ve thought about
We’ll create a new JavaScript method paired with a new UDF to tackle this.
getSomeFromFauna will take an integer count to ask Fauna for a certain number of items.
Our UDF will be very similar to the getLatestFromFauana UDF. Instead of returning the first item, we’ll Take() the number of items from our array that matches the integer that gets passed into our UDF. We’ll also begin with the same conditional, in case a user doesn’t have any items stored yet.
Query(
Lambda(
["count"]// Number of items to return
If( // Check if there are any objects
GT(
Count(
Select(
"data",
Paginate(Match(Index("getMindfulByUserReverse"), Identity(null)))
)
),
0
),
Let(
{
match: Paginate(
Match(Index("getMindfulByUserReverse"), Identity(null)) // Search the Index by our User
),
latestObjs: Select("data", Take(Var("count"), Var("match"))), // Get the data that is returned
mergedObjs: Map( // Loop over the objects
Var("latestObjs"),
Lambda(
"latestArray",
Let( // Build the data like we did in the LatestMindful function
{
ref: Select(["data"]Get(Select([1]Var("latestArray")))),
latestTime: Select(0, Var("latestArray")),
merged: Merge(
{ latestTime: Var("latestTime") },
Select("mindful", Var("ref"))
)
},
Var("merged") // Return this to our new array
)
)
)
},
Var("mergedObjs") // return the full array
),
{ latestMindful: [{ title: "No additional data" }] } // if there are no items, send back a message to display
)
)
)
In this demo, we created a full-fledged app with serverless data. Étant donné que les données sont servies à partir d'un CDN, elles peuvent être aussi proches que possible d'un utilisateur. We used FaunaDB’s features, such as UDFs and Indexes, to optimize our database queries for speed and ease of use. We also made sure we only queried our database the bare minimum to reduce requests.
Where To Go With Serverless Data
The JAMstack isn’t just for sites. Il peut également être utilisé pour des applications robustes. Whether that’s for a game, CRUD application or just to be mindful of your surroundings you can do a lot without sacrificing customization and without spinning up your own non-dist database system.
With performance on the mind of everyone creating on the JAMstack — whether for cost or for user experience — finding a good place to store and retrieve your data is a high priority. Find a spot that meets your needs, those of your users, and meets ideals of the JAMstack.