https://d226lax1qjow5r.cloudfront.net/blog/blogposts/full-stack-nexmo-with-express-react-dr/Full-Stack-Nexmo-App-with-Express-and-React.png

Erstellen einer Full Stack Nexmo App mit Express und React

Zuletzt aktualisiert am May 12, 2021

Lesedauer: 13 Minuten

Mit dem JavaScript Nexmo Client SDK können Sie eine Front-End-Anwendung bereitstellen, die es den Benutzern ermöglicht, die Unterhaltungen zu steuern, an denen sie beteiligt sind. A Nexmo-Gespräch kann zwei Benutzer oder viele, und mehrere verschiedene Medien verwenden. Wenn Sie den Teilnehmern die Kontrolle über die Elemente der Konversation überlassen, eröffnen sich noch mehr Möglichkeiten für Ihre App.

React ist eine sehr beliebte Wahl für die Erstellung von Anwendungen für das Frontend, und Konzepte wie Conversations und Users im Nexmo Client SDK lassen sich gut auf React-Komponenten mit ihren eigenen zustandsabhängigen Steuerelementen abbilden. Es gibt jedoch einige Dinge, die das Nexmo Client SDK nicht kann, und so ergibt sich das vollständige Bild Ihrer Anwendung erst, wenn wir auch das Back-End betrachten. Mit Express können Sie ein paar einfache Routen hinzufügen, um Ihr Frontend bei der Verwaltung von Benutzern zu unterstützen und alle anderen Aufgaben zu erledigen, die Ihrer Meinung nach am besten auf dem Server erledigt werden sollten.

Im Gegensatz zu einer traditionellen, von einem Server bereitgestellten Anwendung ist Ihr React-Frontend eine eigenständige Anwendung, was bedeutet, dass Ihre "Full Stack"-App in Wirklichkeit aus zwei Anwendungen besteht. Jede wird auf ihrem eigenen Port lauschen und auf Anfragen antworten, ohne sich bei der anderen Seite anzumelden. Aus der Perspektive der Dateistruktur sieht dies wie eine Anwendung innerhalb einer Anwendung aus. Sie richten Ihren Express-Server im Stammverzeichnis Ihres Verzeichnisses ein und fügen dann die React-Anwendung - komplett mit ihrer eigenen separaten package.json-in ein Unterverzeichnis.

Einrichtung der Anwendung

In der Wurzel des Projektverzeichnisses erstellen Sie zunächst ein package.json für Ihre Express-Anwendung und ein server.js das sie enthalten wird. Außerdem müssen Sie eine .env Datei zu erstellen, in der Ihre sensiblen Anwendungs- und Account-Anmeldedaten gespeichert werden. Sie müssen ein paar Pakete von npm: Express, body-parser, dotenv, und natürlich das Nexmo Node SDK:

npm install -s express body-parser dotenv nexmo@beta

Damit Sie beide Applications gleichzeitig starten können, müssen Sie auch concurrently als Dev-Abhängigkeit installiert haben:

npm install --save-dev concurrently

Als nächstes geben Sie die Schlüssel, IDs und Geheimnisse an, die zur Identifizierung Ihrer Nexmo-Anwendungbenötigt werden, die Sie in Ihrer .env Datei speichern können:

API_KEY="" API_SECRET="" APP_ID="" PRIVATE_KEY="/private.key"

Sie finden Ihren API-Schlüssel und Ihr Geheimnis auf der Seite Erste Schritte Seite Ihres Nexmo Dashboards. Sie erhalten eine Anwendungs-ID und einen generierten privaten Schlüssel zum Herunterladen auf der Seite Anwendung erstellen (wenn Ihre Anwendung für Nachrichten gedacht ist, können Sie die Seite Nachrichten-Anwendung erstellen Seite verwenden). Im Beispiel wird der private Schlüssel im Stammverzeichnis Ihres Verzeichnisses gespeichert; stellen Sie also sicher, dass Sie den Pfad in .env wenn Sie ihn an einen anderen Ort verschieben.

Nachdem Sie diese Einrichtung abgeschlossen haben, können Sie mit der Erstellung der Client-App fortfahren.

Eine React-App erstellen

Sie können schnell ein Gerüst für Ihren Client erstellen, indem Sie die sehr praktische create-react-app. Da diese React-Anwendung in einem Unterverzeichnis Ihres Projekts liegen wird, können Sie den Namen des Unterverzeichnisses angeben, wenn Sie den Befehl ausführen (obwohl Sie den Namen der Anwendung vielleicht in etwas Beschreibenderes ändern möchten, sobald sie ihre package.json). In unserem Beispiel haben wir das Unterverzeichnis "client" genannt:

npx create-react-app client

Damit erhalten Sie das meiste, was Sie auf dem Client benötigen, einschließlich der React-Abhängigkeiten und einer Reihe von Skripten, um Dinge wie das Starten und Erstellen Ihrer App zu erledigen. Das einzige zusätzliche Paket, das Sie von npm benötigen, ist das Nexmo Client SDK:

npm install -s nexmo-client@beta

In Ihrem Client package.json müssen Sie auch einen Proxy hinzufügen, der auf Ihren Express-Server und den Port verweist, an dem er läuft:

"proxy": "http://localhost:3001",

Express-Server

Die Initialisierung Ihres Express-Servers sollte Ihnen bekannt vorkommen, wenn Sie bereits mit Express gearbeitet haben. Sie benötigen auch dotenv und body-parserbenötigen, die Sie als Middleware mit Ihrer Anwendung verbinden werden:

require('dotenv').config();

// init server
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());

Als Nächstes müssen Sie einen neuen Nexmo-Client erstellen und ihm die Variablen übergeben, die Sie in Ihrer .env Datei gespeichert haben, die dotenv als Mitglieder von process.env:

// create a Nexmo client
const Nexmo = require('nexmo');
const nexmo = new Nexmo({
  apiKey: process.env.API_KEY,
  apiSecret: process.env.API_SECRET,
  applicationId: process.env.APP_ID,
  privateKey: __dirname + process.env.PRIVATE_KEY 
}, {debug: true});

In diesem einfachen Beispiel erstellen wir nur Endpunkte zum Abrufen eines JWT und zum Erstellen eines neuen Benutzers. Sie können die Signaturen Ihrer Endpunkte jetzt definieren, und wir werden die Logik für beide Anwendungen zusammen in einem späteren Schritt bereitstellen. Zum Schluss wollen Sie natürlich, dass Ihr Express-Server auf dem Port lauscht, den Sie in Reacts package.json:

app.post('/getJWT', function(req, res) {});
app.post('/createUser', function(req, res) {});

app.listen(3001);

React-App-Komponente

Wenn Sie create-react-appausgeführt haben, sollte es einen Einstiegspunkt zu Ihrer Anwendung unter src/index.js in Ihrem Client-Unterverzeichnis. Dadurch wird die Komponente geladen, die in src/App.js definierte Komponente und rendert sie als Body Ihrer Landing Page. Diese Komponente ist ein idealer Ort, um administrative Aufgaben wie das Abrufen eines JWT und das Einloggen in Ihre Nexmo-Anwendung zu erledigen. Sie ist auch ein guter Container für zwei untergeordnete Komponenten: User und Conversation. Zu Beginn importieren Sie zwei Komponenten, die Sie gleich erstellen werden:

import React from 'react';
import User from './User';
import Conversation from './Conversation';

import nexmoClient from 'nexmo-client';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    
    this.login = this.login.bind(this);
    this.getJWT = this.getJWT.bind(this);
    this.userUpdated = this.userUpdated.bind(this);
  }
    
  login() {}  
  getJWT() {}  
  userUpdated() {}
  render() {}
    
};

export default App;

Wie Sie sehen können, haben wir auch das Nexmo Client SDK importiert und die erstellte Klasse bereinigt, damit sie mit unserer Logik gefüllt werden kann. Wir haben auch Platzhalter für die Funktionen, die wir benötigen, hinzugefügt.

Da Sie nun Referenzen zu den beiden untergeordneten Komponenten haben (auch wenn wir sie noch nicht erstellt haben), können Sie Ihre Renderfunktion aktualisieren, um sie auf Ihrer Seite zu laden:

render() {
  return (
    <div className="nexmo">
      <User onUpdate={this.userUpdated} />
      <Conversation app={this.state.app} loggedIn={!!this.state.token} />
    </div>
  );
}

Anmeldung bei der Nexmo-Anwendung

Die Komponente User Komponente wird die Funktion userUpdated aufrufen, wenn sie Änderungen an ihrem Zustand melden will, so dass diese Funktion das erste Glied in Ihrer Ausführungskette wird. Sie suchen nach einer username Eigenschaft des empfangenen Zustandsobjekts, und wenn diese existiert, fahren Sie fort, um ein JWT für diesen Benutzer zu erhalten:

userUpdated(user) {
  if (user.username) {
    this.getJWT(user.username);
  }
}

Ihre getJWT Funktion wird hauptsächlich aus einer fetch und der Behandlung ihrer Antwort bestehen. Sie müssen POST den Benutzernamen, den die Funktion erhält, als JSON an den Express-Server senden, dann die Daten analysieren und Ihr neues JWT als Statuseigenschaft speichern token. Wenn das erledigt ist, können Sie die login Funktion aufrufen, um die Initialisierung Ihrer Anwendung abzuschließen:

getJWT(username) {
  fetch('/getJWT', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({name: username})
  })
  .then(results => results.json())
  .then(data => {
    this.setState({
      token: data.jwt
    });
    this.login();
  });
}

Abrufen eines JWT vom Server

Springen wir ganz schnell zurück zu Ihrer Express-App in server.js und stellen den Endpunkt bereit, den die clientseitige getJWT Funktion aufrufen wird. Die Verwendung des Nexmo Node SDKkönnen wir ein JWT generieren, indem wir wieder unsere Anwendungs-ID angeben, den suboder Benutzernamen, den wir vom Client senden, eine Ablaufzeit in Sekunden und die Berechtigungen die dieses Token haben soll. Im folgenden Code kann der Benutzer Dinge tun, die mit Benutzer, Unterhaltungen, Sitzungen und Applications zu tun haben, was für unsere sehr einfache App ausreicht:

app.post('/getJWT', function(req, res) {
  const jwt = nexmo.generateJwt({
    application_id: process.env.APP_ID,
    sub: req.body.name,
    exp: Math.round(new Date().getTime()/1000)+3600,
    acl: {
      "paths": {
        "/v1/users/**":{},
        "/v1/conversations/**":{},
        "/v1/sessions/**":{}
      }
    }
  });
  res.send({jwt: jwt});
});

Da Ihr Server nun ein Token an die React-App sendet, können Sie zu App.js zurückkehren und die Logik für Ihre letzte Funktion bereitstellen, login. Es gibt wirklich nicht viel zu tun. Mit dem neuen Token, das im Status der App-Komponente gespeichert ist, melden Sie sich am Nexmo-Client an und erhalten einen Verweis auf Ihre eingeloggte Nexmo-App. Diesen können Sie im Status der Komponente speichern, und damit ist die Komponente fertig!

login() {
  let nexmo = new nexmoClient();
  nexmo.createSession(this.state.token).then(app => {
    this.setState({
      app: app
    });
  });
}

React-Benutzer-Komponente

Da Ihre App-Komponente auf die User-Komponente wartet, um den Login-Flow auszulösen, sollten wir diese Komponente jetzt erstellen. In einer neuen User.js Datei in demselben Verzeichnis wie App.jskönnen Sie einen Umriss der Komponente erstellen:

import React from 'react';

class User extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    
    this.createUser = this.createUser.bind(this);
    this.setUsername = this.setUsername.bind(this);
  };
  
  createUser() {}
  setUsername() {}
  render() {}
    
};

export default User;

In einer realen Anwendung würden Sie ein System zur Verwaltung und Speicherung Ihrer Benutzer sowie zu deren Authentifizierung verwenden wollen. In diesem minimalen Beispiel werden Sie jedoch einfach bei jedem Zugriff auf diese Seite einen neuen Benutzer anlegen. In Ihrer render Funktion können Sie prüfen, ob der Zustand der Komponente eine userId Eigenschaft enthält. Wenn ja, können Sie eine Meldung ausgeben, die bestätigt, dass der Benutzer eingeloggt ist. Wenn nicht, können Sie ein Textfeld und eine Schaltfläche zum Anlegen des neuen Benutzers anzeigen:

render() {
  if (this.state.userId) {
    return (
      <div className="userinfo userconnected">
        Connected as <span className="username">{this.state.username}</span>
      </div>
    );
  } else {
    return (
      <div className="userinfo">
        <input type="text" onChange={evt => this.setUsername(evt)} />
        <button onClick={this.createUser}>Create user</button>
      </div>
    );
  }
}

Neue Benutzer anlegen

Die Erstellung des Benutzers ist eigentlich ein zweiteiliger Prozess, der damit beginnt, auf Änderungen am Text in Ihrem Textfeld zu achten und den aktualisierten Wert zu speichern. Wenn Sie diese Anwendung robuster gestalten wollten, könnten Sie damit beginnen, diesen Wert mit den Regeln für den Benutzernamen und der Liste der vorhandenen Benutzer abzugleichen und dem Benutzer über eine Änderung des Stylings Gültigkeits- oder Duplikationsprobleme mitzuteilen. Aber für dieses Beispiel werden wir einfach naiv den Text speichern, den der Benutzer eingetippt hat:

setUsername(evt) {
  this.setState({
    username: evt.target.value
  });
}

Sobald der Benutzer auf die Schaltfläche "Benutzer erstellen" klickt, können Sie eine weitere Anfrage an Ihren Express-Server senden. Sie senden den Benutzernamen, wie er im Status von setUsernamegespeichert ist, und wenn der Server antwortet, lösen Sie die onUpdate Funktion aus, die von der App Komponente bereitgestellt wird, wenn diese Komponente instanziiert wurde:

createUser() {
  fetch('/createUser', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({name: this.state.username})
  })
  .then(results => results.json())
  .then(data => { 
    this.setState({
      userId: data.id
    }, () => this.props.onUpdate(this.state));
  });
}

Der createUser Endpunkt ist der letzte Teil des Express-Servers, den wir noch bereitstellen müssen, also gehen wir zurück zu server.js und füllen diese Logik aus. Sie können users.create auf Ihrem Nexmo-Objekt aufrufen und dabei den Benutzernamen vom Client und einen optionalen Anzeigenamen übergeben (den wir nicht in den Client-Code für diese Anwendung aufgenommen haben, den Sie aber später angeben können). Wenn das erfolgreich ist, wird die ID des neuen Benutzers an den Client zurückgegeben:

app.post('/createUser', function(req, res) {
  nexmo.users.create({
    name: req.body.name,
    display_name: req.body.display_name || req.body.name
  },(err, response) => {
    if (err) {
      res.sendStatus(500);
    } else {
      res.send({id: response.id});
    }
  });
});

Jetzt ist die gesamte Logik, die Sie für die Erstellung eines Benutzers sowohl in Ihrer React- als auch in Ihrer Express-Anwendung benötigen, verfügbar, so dass Ihre React-Anwendung in der Lage ist, sich anzumelden und Dinge wie das Erstellen einer Konversation zu tun.

React-Konversationskomponente

Die letzte Datei, die Sie erstellen müssen, ist Conversation.jsin demselben Verzeichnis wie App.js und User.js. Der Umriss der Komponente ist sogar noch kleiner als die beiden, die Sie bereits erstellt haben, aber in einer realen Anwendung würde es sich wahrscheinlich um die Komponente handeln, die die meiste Logik und wahrscheinlich sogar mehrere untergeordnete Komponenten enthält:

import React from 'react';

class Conversation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    
    this.createConversation = this.createConversation.bind(this);
  }
  
  createConversation() {}
  render() {}
    
};

export default Conversation;

Die Funktion dieser Komponente render Funktion muss eigentlich nur eine Schaltfläche bereitstellen, aber Sie können es ein wenig schöner machen, indem Sie die Schaltfläche deaktivieren, bis die App Komponente dies meldet Conversation dass sie ihre Initialisierungsarbeit erledigt hat. Sie können dann die Schaltfläche ausblenden, sobald die Konversation beigetreten ist und ein Verweis auf sie im Zustand der Komponente gespeichert ist:

render() {
  if (this.state.conversation) {
    return (
      <div className="conversation">Joined conversation!</div>
    );
  } else {
    return (
      <div className="conversation">
        <button 
          onClick={this.createConversation} 
          disabled={!this.props.loggedIn}>Start conversation</button>
      </div>
    );
  }
}

Der größte Teil der Logik der createConversation Funktion beruht auf den Objekten Nexmo Application und Conversation. Wenn der Benutzer auf die Schaltfläche klickt, können Sie eine neue Unterhaltung mit einem Aufruf der app Eigenschaft, die an diese Komponente übergeben wird. Das gibt eine Konversation zurück, der Sie beitreten können und die Sie dann als Statuseigenschaft speichern können:

createConversation() {
  this.props.app.newConversation().then(conv => {
    conv.join().then(member => {
      this.setState({
        conversation: conv
      });
    });
  });
}

Von hier aus können Sie andere Benutzer zur Konversation einladen, Handler für Konversationsereignisse bereitstellen oder einen Audiostream öffnen, damit die Teilnehmer miteinander sprechen können.

Starten der Apps

Sie wollen in der Lage sein, Ihre Express- und React-Applikationen so zu starten, als ob sie eine einzige wären, und deshalb müssen Sie als Letztes den Mechanismus bereitstellen, mit dem sie zusammen starten können. Sie haben bereits React's package.json so bearbeitet, dass sie die Express-App kennt; jetzt ist es an der Zeit, einige Skripte zu Express's package.json hinzuzufügen, damit npm start tatsächlich alles startet.

Im Verzeichnis package.json im Stammverzeichnis Ihres Projekts fügen Sie drei Skripte hinzu oder ändern sie: start, client, und server:

"scripts": {
    "client": "cd client && npm start",
    "server": "node server.js",
    "start": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\""
  },

Das concurrently Paket, das Sie zu Beginn dieses Tutorials installiert haben, startet den Express-Server gleichzeitig mit der Navigation in das Client-Verzeichnis (beachten Sie, dass Sie "client" in den Namen Ihres React-Unterverzeichnisses ändern müssen, wenn Sie es anders genannt haben) und führt das start Skript aus, das von create-react-app. Wenn Sie npm start ausführen, sollten Sie in der Lage sein, einen Browser zu öffnen, der die React-Anwendung unter http://localhost:3000 öffnen und Ihre Anwendung laufen sehen.

Möchten Sie eine etwas komplexere Version dieser Anwendung in Aktion sehen? Sie können den erweiterten Code auf Glitch ansehen ansehen und ihn nachbauen, um weiter mit Nexmo Conversations zu experimentieren. Und jetzt, wo du die Grundlagen kennst, kannst du weitermachen und eine Chat-App mit React und Nexmo zu bauen.

Teilen Sie:

https://a.storyblok.com/f/270183/250x250/f231d97f1b/garann-means.png
Garann MeansEntwickler Pädagoge

Ich bin ein JavaScript-Entwickler und ein Developer Educator bei Vonage. Im Laufe der Jahre habe ich mich für Templates, Node.js, progressive Web-Apps und Offline-First-Strategien begeistert, aber was ich immer geliebt habe, ist eine nützliche, gut dokumentierte API. Mein Ziel ist es, Ihre Erfahrung mit unseren APIs so gut wie möglich zu gestalten.