목표는 다른 서비스와 함께 Ally Realtime을 사용하여 전체 기능 세트가있는 채팅 앱을 구축하여 데이터를 저장, 조작 및 공유하는 것입니다.
궁금한 점, 아이디어가 있거나 기여하고 싶다면 문제를 제기하거나 당사에게 연락하십시오.
노드 16 설치
Azure는 NPM에서 런타임을 기능합니다. 이 실행을 설치하려면 :
npm install -g azure-functions-core-tools@4
.env 파일 ./api :
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 파일에서 볼 수 있듯이 현재 양식으로 프로젝트를 사용하려면 가입해야 할 몇 가지 서비스가 있습니다.
충분한 자격 증명을 얻으려면 먼저 무료 계정에 가입해야합니다. 일단 ABLE 계정이 있으면 생성 된 기본 앱으로 이동하여 루트 API 키를 얻을 수 있습니다. 이것은 ABLY_API_KEY 환경에 사용됩니다. APP_ID env 변수는 풀 스톱 전에 API 키의 첫 번째 부분으로 설정해야합니다. API 키가 12345.jh40fj23jkd0-,32c3-j- 인 경우 12345 로 설정해야합니다.
API 키, 앱 및보다 프로그래밍 방식으로 생성하는 데 사용되는 CONTROL_KEY 의 경우 로그인 한 사용자로서 액세스 토큰으로 이동하여 '새 액세스 토큰 작성'을 클릭해야합니다. '계정'드롭 다운에서 이름을 지정하십시오. API 키가있는 앱이있는 계정을 선택하고 read:key 및 write:key 권한을 선택하십시오. 토큰을 만들고 그 값을 CONTROL_KEY 로 사용하십시오.
COSMOSDB는이 앱의 데이터를 저장하는 데 사용됩니다. Azure 계정을 얻고 COSMOSDB 리소스를 만들려면 Azure의 설정 자습서의 단계를 따르십시오. COSMOS_ENDPOINT 새로운 Subaccount에서 제공 한 URI로 설정해야합니다. COSMOS_KEY 는 COSMOSDB 계정의 주요 키이며 Azure에서 설명한대로 액세스 할 수 있습니다.
COSMOS_DATABASE_ID 는 COSMOSDB 계정 내에서 사용할 컨테이너의 이름입니다.
COSMOSDB에 생성 된 동일한 Azure 계정을 사용하여 새 데이터 스토리지 컨테이너를 만듭니다. 해당 설정이 있으면 사이드 바의 '액세스 키'섹션으로 이동하여 AZURE_STORAGE_CONNECTION_STRING 의 connection string 얻은 다음 AZURE_STORAGE_CONTAINER_NAME 컨테이너라는 이름으로 설정하십시오.
Auth0을 인증 방법으로 포함하려면 Auth0 계정을 만들어야합니다. Auth0 계정이 있으면 응용 프로그램 유형으로 선택한 '일반 웹 응용 프로그램'이있는 응용 프로그램을 만듭니다. 이 앱에서는 AUTH0_DOMAIN 의 도메인을 복사하고 AUTH0_CLIENTID 의 ClientId를 복사 할 수 있습니다. AUTH0_REDIRECT_URI 사용자를 인증 한 후 auth0이 리디렉션 해야하는 적절한 URI를 가리켜 야합니다. 기본값은 로컬에서 실행하기 위해 작동해야합니다.
Auth0 앱의 설정 탭에서 'Application Uris'라는 섹션으로 스크롤하십시오. 그것에는 '허용 된 콜백 URL'및 '허용 로그 아웃 URL'에 대한 필드가 표시되어야합니다. 컨텍스트의 경우 Auth0을 사용하는 웹 페이지의 흐름은 다음과 같습니다.
귀하의 사이트는 사용자를 Auth0 앱의 로그인 페이지에 연결하여 Auth0 페이지에 로그인하여 사용자가 로그 아웃 할 때 사용자를 웹 사이트의 '콜백'페이지로 다시 리디렉션하면 Auth0 앱의 로그 아웃 페이지로 이동 한 다음 로그 아웃 페이지에 통과 된 'ReturnTo'쿼리에 지정된 페이지로 다시 리디렉션됩니다.
잠재적 오용 및 남용을 피하려면 URLS Auth0이 리디렉션 할 수있는 내용을 지정해야합니다. 이 채팅 앱을 로컬로 호스팅 할 때 LocalHost : 8080에서 호스팅되므로 허용 콜백 URL을 'http : // localhost : 8080/auth0-landing'으로 설정하십시오. 사용자가 로그 아웃하면 사용자가 메인 페이지로 다시 리디렉션되므로 허용되는 로그 아웃 URL을 'http : // localhost : 8080/'로 설정하십시오.
채팅 앱은 다음으로 구성됩니다.
Archive APIChat Archive 저장하는 스토리지 버킷. React 응용 프로그램은 기본 단일 페이지 응용 프로그램입니다. react-router-dom 과 맞춤형 AppProvider 를 사용하여 응용 프로그램의 보안 컨텍스트를 제공합니다.
이 앱은 @ably-labs/react-hooks를 사용하여 ably 채널 과 상호 작용하며 응용 프로그램은 최신 반응 기능 구성 요소 로 구성됩니다.
Snowpack 은 개발 서버로, 생산을위한 ES6 코드를 투명하게 구축합니다.
BFF는 채팅 앱의 모든 서버 사이드 로직을 포함하는 응용 프로그램 특정 API입니다. Azure 정적 웹 앱 에서 호스팅되므로 azure-functions-core-tools 사용할 수 있습니다.
이 외에도 Azure 정적 웹 앱 런타임은 API를 자동 호스트 하므로 호스팅 구성에 대해 걱정할 필요가 없습니다. BFF는 Serverless Infruascutre에서 실행되며 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 API를 만들어야합니다.
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는 코드를 변경할 때 코드를 자동화하고 기능을 재건합니다.
이 앱은 웹 응용 프로그램과 BFF 간의 JWT 토큰 인증을 사용합니다. 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 ; 위의 예제는 Component Mants -API 요청이 useAuth 후크에서 제공하는 api 인스턴스를 사용하여 작성된 경우 useEffect 후크를 사용하여 채널을 가져옵니다.
이것은 JWT 토큰이 유효하고 존재하는지 확인하기 때문에 구성 요소에서 BFF로 API 호출을하는 유일한 방법입니다.
애플리케이션에 새 BFF APIs 추가하는 경우 구성 요소에서 사용할 수 있도록 /app/src/sdk/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 )를 사용하여 이러한 엔티티를로드하고 저장합니다.
로컬 개발의 경우 클라우드 호스팅 버전의 코스모어를 사용하거나 사용 가능한 docker container images 중 하나를 사용하여 로컬 데이터베이스 사본을 실행할 수 있습니다.
우리는 채팅 메시지를 저장하고 이벤트를 React 애플리케이션으로 푸시하기 위해 Ably channels 사용하고 있습니다. 각 연결된 사용자는 실시간으로 적극적으로보고있는 채널에 대한 메시지를 수신 할 것이며, Channel rewind 사용하여 가장 최근에 보낸 메시지를 채우고 있습니다.
예를 들어 욕설 필터링을 적용하거나 철자 오류를 수정하기 위해 수신 된 후 메시지를 비동기 적으로 corrected 수 있습니다. 이 보정 메시지는 스트림의 일부가되며 React 응용 프로그램에서 소급 적용됩니다. (이후의 서사시에서 이것에 대한 추가 개발)
이 디자인을 통해 이러한 이벤트를 소비하는 추가 API를 견딜 수 있으며 고객이 응답 할 수 있도록 채널에 대한 자체 정교함을 게시 할 수 있습니다.
Ally 이벤트는 시간이 지남에 따라 사라질 것이므로 각 채널의 인바운드 이벤트 사본을 Archive API 통해 Chat Archive 에 저장할 것입니다.
Archive API 모든 채널에 대한 원자로 메시지를 수신하여 채널 별 Azure Storage Blobs 에 추가됩니다. API는 크기 임계 값 (~ 500KB)에 도달 할 때까지 단일 파일에 추가 된 다음 후속 메시지에 새 파일을 만듭니다.
Archive API 각 채널의 Metadata database 에서 현재 활성 아카이브 파일의 레코드를 유지합니다.
Archive API 메시지를 수신하고 보관하여 검색에 노출되면 검색 인덱스를 업데이트 할 수 있습니다.
테스트는 APIS TypeScript 테스트를 실행하는 데 사용되는 ts-jest 와 함께 jest 로 작성됩니다.