
シェア:
私はJavaScript開発者で、Vonageの開発者教育者です。長年にわたり、テンプレート、Node.js、プログレッシブ・ウェブ・アプリケーション、そしてオフライン・ファースト戦略に熱中してきましたが、私がいつも本当に愛しているのは、便利できちんと文書化されたAPIです。私の目標は、当社のAPIを使用するお客様の体験を、私がお手伝いできる最高のものにすることです。
ExpressとReactでフルスタックのNexmoアプリを作る
JavaScriptのNexmo Client SDKを使用すると、ユーザーが参加する会話をコントロールできるフロントエンドアプリケーションを提供できます。A Nexmo会話には2人の ユーザーを含むことができ、複数の異なるメディアを使用することができます。参加者に会話の要素をコントロールさせることで、アプリが提供できる選択肢が広がります。
ReactNexmoクライアントSDKのConversationsやUsersのようなコンセプトは、独自のステートフルコントロールを持つReactコンポーネントにうまくマッピングされます。しかし、Nexmo Client SDKではできないこともあり、バックエンドを考慮しないとアプリケーションの全体像が見えてきません。Expressを使うことで、フロントエンドのユーザー管理をサポートする簡単なルートをいくつか追加することができます。
従来のサーバーが提供するアプリケーションとは異なり、Reactフロントエンドはそれ自体がアプリケーションであり、「フルスタック」アプリケーションは実際には2つのアプリケーションであることを意味する。つまり、"フルスタック "アプリは、実際には2つのアプリケーションであるということだ。それぞれが独自のポートでリッスンし、もう一方とチェックインすることなくリクエストに応答する。ファイル構造の観点から見ると、これはアプリの中のアプリということになる。ディレクトリのルートにExpressサーバーをセットアップし、サブディレクトリにReactアプリを追加します。 package.json-をサブディレクトリに追加します。
アプリケーションのセットアップ
プロジェクト・ディレクトリのルートで、まずExpressアプリ用の package.jsonを作成します。 server.jsを作成します。また .envファイルを作成し、アプリケーションとアカウントの認証情報を保存します。からいくつかのパッケージをインストールする必要があります。 npm: Express, ボディパーサー, dotenvそしてもちろん Nexmo Node SDK:
両方のアプリケーションを一度に起動するには、開発依存として concurrentlyをdev依存としてインストールする必要がある:
次に、あなたのアプリケーションを識別するために必要なキー、ID、およびシークレットを提供します。 Nexmoアプリケーションを提供します。 .envファイルに保存できます:
APIキーとシークレットは 入門ページで確認できます。アプリケーションIDと生成された秘密鍵は、以下のページからダウンロードできます。 アプリケーションの作成(アプリケーションIDと生成された秘密鍵は、アプリケーションの作成ページからダウンロードできます。 メッセージアプリケーションの作成ページからダウンロードできます。)この例では、秘密鍵はディレクトリのルートに保存されています。 .envのパスを更新してください。
セットアップが完了したら、クライアント・アプリの作成に移ることができる。
Reactアプリの作成
とても便利な create-react-app.このReactアプリはプロジェクトのサブディレクトリに置かれるので、コマンドを実行するときに好きなサブディレクトリ名を指定できます(ただし、Reactアプリが生成されたら、アプリケーション名をもっとわかりやすいものに変更したくなるかもしれません)。 package.json).この例では、サブディレクトリを "client "と呼んでいます:
これにより、Reactの依存関係や、アプリの起動やビルドなどを行うスクリプトのセットなど、クライアントに必要なもののほとんどが手に入る。npmから必要な唯一の追加パッケージは NexmoクライアントSDK:
クライアントで package.jsonプロキシを追加して、Expressサーバーとそのポートを参照するようにします:
"proxy": "http://localhost:3001", エクスプレス・サーバー
Expressサーバーの初期化は、Expressを扱ったことがある人であれば慣れているはずです。また dotenvと body-parser後者はミドルウェアとしてアプリにアタッチする:
require('dotenv').config();
// init server
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());次に、新しいNexmoクライアントを作成します。 .envファイルに保存した変数を dotenvのメンバーとしてアクセスできるようにします。 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});この単純な例では、JWTを取得して新しいユーザーを作成するためのエンドポイントだけを作成します。エンドポイントのシグネチャは今すぐ定義でき、後のステップで両方のアプリのロジックを一緒に提供します。最後に、もちろん、Reactの package.json:
app.post('/getJWT', function(req, res) {});
app.post('/createUser', function(req, res) {});
app.listen(3001); リアクト・アプリケーション・コンポーネント
を実行したとき create-react-appを実行したとき、アプリケーションへのエントリー・ポイントがクライアント・サブディレクトリの src/index.jsにエントリーポイントが作成されるはずです。これは src/App.jsで定義されたコンポーネントをロードし、ランディングページのボディとしてレンダリングします。このコンポーネントは、JWTの取得やNexmoアプリケーションへのログインなどの管理タスクを行うのに理想的な場所です。また、2つの子コンポーネントの良いコンテナでもあります: Userそして Conversation.まず始めに、これから作成する2つのコンポーネントをインポートします:
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;ついでに、Nexmo Client SDKもインポートし、作成したクラスをクリーンアップして、ロジックを入力できるようにしています。必要な関数のプレースホルダも追加しました。
これで2つの子コンポーネントへの参照ができたので(まだ作成していませんが)、レンダー関数を更新してページに読み込むことができます:
render() {
return (
<div className="nexmo">
<User onUpdate={this.userUpdated} />
<Conversation app={this.state.app} loggedIn={!!this.state.token} />
</div>
);
}
Nexmoアプリケーションへのログイン
コンポーネントは Userコンポーネントは userUpdatedそのため、この関数は実行チェーンの最初のリンクになります。受け取ったステートオブジェクトの usernameプロパティを探し、それが存在すれば、そのユーザーのJWTを取得します:
userUpdated(user) {
if (user.username) {
this.getJWT(user.username);
}
}あなたの getJWT関数のほとんどは fetchとその応答の処理で構成されます。必要なのは POST関数が受け取ったユーザー名をJSONとしてExpressサーバーに送信し、そのデータを解析して新しいJWTをstateプロパティとして保存します。 token.これで login関数を呼び出して、アプリケーションの初期化を終了します:
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();
});
}
サーバーからJWTを取得する
でExpressアプリに戻り、クライアント側のエンドポイントを提供しよう。 server.jsに戻り、クライアント側の getJWT関数を呼び出します。NexmoノードSDKを使用して Nexmo Node SDKを使用して、もう一度アプリケーションIDを提供することでJWTを生成できます。 sub秒単位の有効期限、そして パーミッションを指定することでJWTを生成できます。以下のコードでは、ユーザはユーザ、会話、セッション、アプリケーションに関わることができます:
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});
});これで、サーバーがReactアプリにトークンを送信するようになった。 App.jsに戻り、最終関数のロジックを記述します、 login.やることはそれほど多くない。Appコンポーネントのstateに保存された新しいトークンを使って、Nexmoクライアントにログインし、ログインしたNexmoアプリへの参照を受け取ります。それをコンポーネントのステートに保存すれば、このコンポーネントは完了です!
login() {
let nexmo = new nexmoClient();
nexmo.createSession(this.state.token).then(app => {
this.setState({
app: app
});
});
}
リアクト・ユーザー・コンポーネント
AppコンポーネントはUserコンポーネントがログインフローをトリガーするのを待っているので、そのコンポーネントを作成しよう。新しい User.jsと同じディレクトリに、新しい App.jsと同じディレクトリにある新しいファイルに、コンポーネントのアウトラインを記述します:
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;実際のアプリケーションでは、ユーザーを管理、保存し、認証するシステムを使いたいでしょう。しかし、この最小限の例では、このページにアクセスするたびに新しいユーザーを作成するだけです。あなたの render関数の中で、コンポーネントのステートに userIdプロパティが含まれているかどうかをチェックできます。もしそうなら、ユーザがログインしていることを確認するメッセージを投稿できます。そうでなければ、新しいユーザを作成するためのテキストフィールドとボタンを表示することができます:
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>
);
}
}
新規ユーザーの作成
ユーザーの作成は、テキストフィールドのテキストの変更をリッスンし、更新された値を保存することから始まる、実際には2つの部分からなるプロセスです。もしこのアプリをより堅牢なものにしたいのであれば、ユーザー名のルールや既存のユーザーリストとその値を照合し、有効性や重複の問題をスタイリングの変更によってユーザーにメッセージすることから始めることもできます。しかし、この例では、ユーザーが入力したテキストを素朴に保存することにします:
setUsername(evt) {
this.setState({
username: evt.target.value
});
}ユーザが "Create user "ボタンをクリックしたら、Expressサーバにリクエストを送信します。で保存されているユーザー名を送信します。 setUsernameに格納されているユーザー名を送信し、サーバーから応答があると onUpdate関数をトリガします。 Appコンポーネントが提供する関数をトリガします:
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));
});
}
エンドポイントは createUserエンドポイントは、Expressサーバーの最後の部分です。 server.jsに戻り、ロジックを埋めていきます。Nexmoオブジェクトに対して users.createを呼び出し、クライアントからのユーザー名とオプションの表示名(このアプリのクライアントコードには含まれていませんが、後で提供することもできます)を渡します。成功すれば、新しいユーザーのIDをクライアントに返します:
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});
}
});
});
これで、ReactアプリとExpressアプリの両方でユーザーを作成するために必要なロジックがすべて利用できるようになり、Reactアプリはログインして会話の作成などを行うことができるようになる。
リアクト会話コンポーネント
最後に作成するファイルは Conversation.jsと同じディレクトリに App.jsと User.js.コンポーネントのアウトラインは、すでに作成した2つよりもさらに小さくなりますが、実際のアプリケーションでは、おそらく最も多くのロジックを含むコンポーネントであり、おそらくいくつかの子コンポーネントも含むでしょう:
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;このコンポーネントの render関数は本当にボタンを提供するだけでよいのですが、このコンポーネントが Appコンポーネントが Conversationに通知するまでボタンを無効にします。そして、会話が参加され、その参照がコンポーネントのステートに保存されると、ボタンを非表示にすることができます:
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>
);
}
}
この createConversation関数の大半はNexmoアプリケーションと会話オブジェクトに依存しています。ユーザがボタンをクリックすると、このコンポーネントに渡された appプロパティへの呼び出しで新しい会話を作成できます。その会話に参加し、ステートプロパティとして保存することができます:
createConversation() {
this.props.app.newConversation().then(conv => {
conv.join().then(member => {
this.setState({
conversation: conv
});
});
});
}
ここから、他のユーザーを会話に招待したり、会話イベントのハンドラを提供したり、オーディオストリームを開いて参加者同士が会話したりすることができる。
アプリの起動
ExpressアプリとReactアプリを、あたかも1つのアプリのように起動できるようにしたいわけですから、最後に必要なのは、それらが一緒に起動する仕組みを提供することです。Reactの package.jsonのスクリプトをExpressの package.jsonにスクリプトを追加します。 npm start実際にすべてが起動するようにするのだ。
プロジェクトのルートにある package.jsonに、3つのスクリプトを追加または変更する: start, clientと server:
"scripts": {
"client": "cd client && npm start",
"server": "node server.js",
"start": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\""
},
このチュートリアルの最初にインストールした concurrentlyこのチュートリアルの冒頭でインストールしたパッケージは、Expressサーバーを起動すると同時に、クライアント・ディレクトリに移動し(「client」をReactサブディレクトリの名前に変更する必要があることに注意してください)、Reactサブディレクトリにある startスクリプトを実行します。 create-react-app.今 npm startにあるReactアプリにブラウザーを開いて、アプリケーションが動いているのを確認できるはずだ。 http://localhost:3000にブラウザーを開き、アプリケーションが動いているのを確認できるはずだ。
このアプリのもう少し複雑なバージョンをご覧になりたいですか?Glitchで Glitchの拡張コードを見るにある拡張コードを見て、Nexmo Conversationsでさらに実験するためにリミックスすることができます。そして、基本的なことがわかったので、次に進むことができます。 ReactとNexmoでチャットアプリを作る.