目標は、他のサービスと組み合わせて、データを保存、操作、共有するために、非常にリアルタイムで完全な機能セットを使用してチャットアプリを構築することです。
ご質問、アイデア、または貢献したい場合は、問題を提起するか、私たちに連絡してください。
ノード16インストール
AzureはNPMからランタイムを機能させます。この実行をインストールするには:
npm install -g azure-functions-core-tools@4
。/apiで.envファイル:
JWT_SIGNING_KEY=key used to sign tokens for users. Can be anything you decide it to be
# Ably
ABLY_API_KEY=YOURKEY:HERE
APP_ID=[YOUR ABLY APP ID](https://faqs.ably.com/how-do-i-find-my-app-id)
CONTROL_KEY=[YOUR ABLY CONTROL KEY](https://ably.com/documentation/control-api#authentication)
# Azure
COSMOS_ENDPOINT=https://yourcosomsdb.documents.azure.com
COSMOS_KEY=ASK FOR THIS OR MAKE YOUR OWN
COSMOS_DATABASE_ID=metadata
AZURE_STORAGE_CONNECTION_STRING=your string here
AZURE_STORAGE_CONTAINER_NAME=container name here
# Auth0
AUTH0_DOMAIN=yourdomain.auth0.com
AUTH0_CLIENTID=yourclientid
AUTH0_REDIRECT_URI=http://localhost:8080/auth0-landing
# from root folder
npm run init # installs node modules for api & integrations
npm run start # runs the dev server.ENVファイルに見られるように、プロジェクトを現在の形式で使用するためにサインアップする必要があるサービスがいくつかあります。
適切な資格情報を取得するには、最初に無料のアカウントにサインアップする必要があります。簡単にアカウントを取得したら、生成されたデフォルトアプリに移動して、ルートAPIキーを取得できます。これは、 ABLY_API_KEY環境に使用されます。 APP_ID ENV変数は、フルストップの前に、APIキーの最初の部分に設定する必要があります。 APIキーが12345.jh40fj23jkd0-,32c3-j-の場合、 12345に設定する必要があります。
APIキー、アプリなどの作成をよりプログラム的に制御するために使用されるCONTROL_KEYの場合、ユーザーに記録されたログインとしてアクセストークンに移動し、[新しいアクセストークンの作成]をクリックする必要があります。 「アカウント」ドロップダウンから名前を付けてください。APIキーを持っているアプリのあるアカウントを選択し、 read:key and write:key permissionsを選択してください。トークンを作成し、その値をCONTROL_KEYとして使用します。
cosmosDBは、このアプリのデータを保存するために使用されます。 Azureアカウントを取得してCOSMOSDBリソースを作成するには、Azureのセットアップチュートリアルの手順に従ってください。 COSMOS_ENDPOINT新しいサブアカウントで提供されるURIに設定する必要があります。 COSMOS_KEY 、cosmosdbアカウントの主要な鍵であり、Azureで説明されているようにアクセスできます。
COSMOS_DATABASE_ID 、cosmosdbアカウント内で使用するコンテナの名前です。
cosmosDB用に作成された同じAzureアカウントを使用して、新しいデータストレージコンテナを作成します。そのセットアップを取得したら、サイドバーの「アクセスキー」セクションに移動して、 AZURE_STORAGE_CONNECTION_STRINGのconnection stringを取得し、 AZURE_STORAGE_CONTAINER_NAMEコンテナに指定したものに設定します。
Auth0を認証方法として含めたい場合は、Auth0アカウントを作成する必要があります。 Auth0アカウントを取得したら、アプリケーションタイプとして選択された「通常のWebアプリケーション」を使用してアプリケーションを作成します。そのアプリでは、 AUTH0_DOMAINのドメインとAUTH0_CLIENTIDのclientidをコピーできます。 AUTH0_REDIRECT_URI 、ユーザーを認証した後、auth0がリダイレクトする必要がある適切なuriを指す必要があります。デフォルト値は、ローカルで実行するために機能する必要があります。
auth0アプリの[設定]タブで、[アプリケーションURIS]と呼ばれるセクションまで下にスクロールします。その中には、「許可されたコールバックURL」および「許可ログアウトURL」のフィールドが表示されます。コンテキストの場合、auth0を使用したウェブページのフローは次のとおりです。
サイトはユーザーをAuth0アプリのログインページにリンクします。そこでは、Auth0ページにサインインしてユーザーがWebサイトの「コールバック」ページにリダイレクトします。ユーザーがログアウトしたいときに、Auth0アプリのログアウトページに向けられ、ログアウトページで指定された「Returnto」クエリで指定されたページにリダイレクトされます。
潜在的な誤用や乱用を回避するには、URLS Auth0がリダイレクトできるものを指定する必要があります。このチャットアプリをローカルでホストする場合、LocalHost:8080でホストされているため、許可されたコールバックURLを「http:// localhost:8080/auth0-landing」に設定します。ユーザーがログアウトすると、ユーザーがメインページにリダイレクトされるため、許可されたログアウトURLを「http:// localhost:8080/」に設定します。
チャットアプリは次のもので構成されています。
Archive API APIを有効な原子炉から受信し、チャット履歴を維持しますChat Archiveを保管するストレージバケット。 Reactアプリケーションは、デフォルトのシングルページアプリケーションです。 react-router-domの混合物とカスタムAppProviderを使用して、アプリケーションのセキュリティコンテキストを提供します。
このアプリは、 @ably-labs/React-hooksを使用して適切なチャネルと対話し、アプリケーションは最新のReact機能コンポーネントで構成されています。
Snowpackは開発サーバーであり、ES6コードを生産用に透過的に構築します。
BFFは、チャットアプリのすべてのサーバーサイドロジックを含むアプリケーション固有のAPIです。 Azure Static Webアプリでホストされているため、 azure-functions-core-tools実行APIサーバーを使用できます。
これに加えて、 Azure Static Web Apps RuntimeはAPIを自動ホストします。そのため、ホスティングの構成を心配する必要はありません。 BFFはServerLess Infrastrucutreで実行され、Azure SWAは需要を満たすために自動スケールします。
新しいAPIエンドポイントを追加するには、 apiフォルダーに新しいディレクトリを追加する必要があります。
まず、新しいAPIのディレクトリを作成します - たとえば、 api/messages 。次に、新しいディレクトリにfunction.jsonファイルを作成します。
{
"bindings" : [
{
"route" : " messages " ,
"authLevel" : " function " ,
"type" : " httpTrigger " ,
"direction" : " in " ,
"name" : " req " ,
"methods" : [ " get " , " post " ]
},
{
"type" : " http " ,
"direction" : " out " ,
"name" : " res "
}
],
"scriptFile" : " ../dist/messages/index.js "
}次に、 TypeScriptを作成する必要があります。
import "../startup" ;
import { Context , HttpRequest } from "@azure/functions" ;
export default async function ( context : Context , req : HttpRequest ) : Promise < void > {
context . res = { status : 200 , body : "I'm an API" } ;
}このAPIは、 http://localhost:8080/api/messagesにマウントされます。
そしてそれだけです!ツールとSDKは、それを変更するときにコードを自動検出し、機能を再構築します。
このアプリは、WebアプリケーションとBFFの間でJWTトークン認証を使用します。ユーザーの資格情報を保存し、Saltedは、cosmosDBデータベースにパスワード(BCRYPTで行われる)をハッシュしました。
ユーザーが認証すると、アプリはユーザーのIDとユーザー名でJWTトークンに署名し、その後の認証データのリクエストでBFFに送信されます。これは、APIに少量のコードを使用すると、ユーザーが自分が主張する人であること、およびAPIデータにアクセスする権利があることを確認できます。
このモデルを拡張して、アプリケーション内のリソースに請求に基づく認証の役割のrolesを含めることができます。
Authenticated User Only API呼び出しを作成しますBFF APIで次の便利な方法を使用して、 JWT token認証API呼び出しを作成できます。
import "../startup" ;
import { Context , HttpRequest } from "@azure/functions" ;
import { authorized , ApiRequestContext } from "../common/ApiRequestContext" ;
export default async function ( context : Context , req : HttpRequest ) : Promise < void > {
await authorized ( context , req , ( ) => {
// This code will only run if the user is authenticated
context . res = {
status : 200 ,
body : JSON . stringify ( "I am validated and authenticated" )
} ;
} ) ;
}これらのAPI呼び出しのいずれかの一部として、認証されたユーザー情報にアクセスする場合は、次のことを行うことができます。
import "../startup" ;
import { Context , HttpRequest } from "@azure/functions" ;
import { authorized , ApiRequestContext } from "../common/ApiRequestContext" ;
export default async function ( context : Context , req : HttpRequest ) : Promise < void > {
await authorized (
context ,
req ,
( { user } : ApiRequestContext ) => {
// user is the userDetails object retrieved from CosmosDb
context . res = {
status : 200 ,
body : JSON . stringify ( "I am validated and authenticated" )
} ;
} ,
true
) ; // <- true to include the userDetails object in the ApiRequestContext
} アプリ内認証は、 AppProviders.jsxに実装されています。
ユーザーが認証されている場合(ユーザーが認証されていることを確認するとともに)、 userDetailsオブジェクトを返すReactフックを提供します。特定のユーザーが認証されていない場合、すべての場合にログインページにリダイレクトされます。
AppProvider認証を処理するため、フックを使用してユーザーデータにアクセスし、任意のコンポーネントで認証されたAPI呼び出しを作成する必要があります。
現在認証されているユーザーのuserDetailsオブジェクトにアクセスする例を以下に示します。
import { useAuth } from "../../AppProviders" ;
const MyComponent = ( ) => {
const { user } = useAuth ( ) ;
return < div > { user . username } </ div > ;
} ;
export default MyComponent ;また、 BffApiClientクラスのインスタンスにアクセスすることもできます。これにより、認証されたAPI呼び出しを行うことができ、現在ログインしているユーザーのJWT tokenが既に含まれています。
import { useAuth } from "../../AppProviders" ;
const MyComponent = ( ) => {
const { api } = useAuth ( ) ;
const [ channels , setChannels ] = useState ( [ ] ) ;
useEffect ( ( ) => {
const fetchChannels = async ( ) => {
const response = await api . listChannels ( ) ;
setChannels ( response . channels ) ;
} ;
fetchChannels ( ) ;
} , [ ] ) ;
return < div > ... bind channel data here </ div > ;
} ;
export default MyComponent ;上記の例では、 useEffectフックを使用してコンポーネントがマウントされたときにチャネルを取得します-APIリクエストは、 useAuthフックが提供するapiインスタンスを使用して行われます。
これは、 JWTトークンが有効かつ存在することを保証するため、コンポーネントからBFFにAPI呼び出しを行う必要がある唯一の方法です。
アプリケーションに新しいBFF APIsを追加する場合は、 /app/src/sdk/BffApiClient.js bffapiclient.jsに新しい関数を実装して、コンポーネントを使用できるようにする必要があります。
これらのBffApiClientコールは簡単で、次のようになります。
async listChannels ( ) {
const result = await this . get ( "/api/channels" ) ;
return await result . json ( ) ;
}クライアントの一部のユーティリティコードは、リクエストが行われたときに正しいJWT tokenが存在することを確認します。
cosmosdbを使用してアプリケーションメタデータを保存します。これは、スケーラブルで非常に利用可能な管理されたデータベースであり、自分で管理する必要がないためです。事前に生成されたモードまたはサーバーレスモードで実行される可能性があり、アプリケーションが使用されていないときにコストを低く抑えることができます(パフォーマンスのコストで)。
単一のcosmosDBデータベースを使用してすべてのメタデータを保存します。内部では、保存しているエンティティの各タイプのコレクションを作成しました。
たとえば、 Userコレクションは、ユーザーレコードを保存し、SQLのような構文を使用して照会できます。 cosmosDBは、JSONドキュメントを自動的にインデックス化することにより、これを簡単にします。
保存されている各メタデータエンティティにはidとtypeフィールドがあり、 generic repositoryクラス( /api/common/dataaccess/CosmosDbMetadataRepository )を使用して、これらのエンティティをロードおよび保存しています。
ローカル開発のために、COSMOSのクラウドホストバージョンを使用するか、利用可能なdocker container imagesいずれかを使用してデータベースのローカルコピーを実行できます。
チャットメッセージを保存し、イベントをReactアプリケーションにプッシュするために、 Ably channelsを使用しています。接続された各ユーザーは、リアルタイムで積極的に表示しているチャネルのメッセージを受信し、最近送信されたメッセージを入力するためにChannel rewindを使用しています。
たとえば、冒とく的なフィルタリングを適用したり、スペルエラーを修正するために、メッセージを受け取った後、メッセージを非同期にcorrected場合があります。これらの修正メッセージは、ストリームの一部であり、Reactアプリケーションに遡及的に適用されます。 (これについては、後の叙事詩でこれに関する開発)
このデザインにより、これらのイベントを消費する追加のAPIを立て、クライアントが応答できるチャネルで独自の精巧さを公開することができます。
うまくイベントが時間の経過とともに消滅するため、各チャンネル上のインバウンドイベントのコピーをArchive APIを介してChat Archiveに保存します。
Archive API 、すべてのチャネルの原子炉メッセージを受信し、チャネル固有のAzure Storage Blobsに追加します。 APIは、サイズのしきい値(〜500kb)に達するまで単一のファイルに追加され、その後のメッセージ用の新しいファイルを作成します。
Archive API各チャネルのMetadata database内の現在アクティブなアーカイブファイルのレコードを維持します。
Archive API 、メッセージが受信され、後で検索でそれらを公開するようにアーカイブされると、検索インデックスを更新できます。
テストは、APIS TypeScriptテストの実行に使用されるts-jestを使用してjestで作成されます。