เป้าหมายคือการสร้างแอพแชทด้วยชุดคุณสมบัติที่สมบูรณ์โดยใช้แบบเรียลไทม์ร่วมกับบริการอื่น ๆ เพื่อจัดเก็บจัดการและแบ่งปันข้อมูล
หากคุณมีคำถามความคิดหรือต้องการมีส่วนร่วมโปรดยกประเด็นหรือติดต่อกับเรา
ติดตั้งโหนด 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 มีบริการไม่กี่อย่างที่คุณจะต้องลงทะเบียนเพื่อใช้โครงการในรูปแบบปัจจุบัน
เพื่อที่จะได้รับข้อมูลประจำตัวที่มีความสามารถคุณจะต้องสมัครใช้งานบัญชีฟรี เมื่อคุณมีบัญชีที่มีความสามารถคุณสามารถไปที่แอพเริ่มต้นที่สร้างขึ้นและรับคีย์รูท API สำหรับมัน สิ่งนี้จะถูกใช้สำหรับสภาพแวดล้อม ABLY_API_KEY ควรตั้งค่าตัวแปร APP_ID env เป็นส่วนแรกของคีย์ API ของคุณก่อน FullStop หากคีย์ API ของคุณคือ 12345.jh40fj23jkd0-,32c3-j- คุณควรตั้งค่าเป็น 12345
สำหรับ CONTROL_KEY ซึ่งใช้สำหรับการควบคุมการสร้างคีย์ API แอพและโปรแกรมมากขึ้นคุณจะต้องไปที่โทเค็นการเข้าถึงในฐานะผู้ใช้ที่เข้าสู่ระบบและคลิก 'สร้างโทเค็นการเข้าถึงใหม่' ให้ชื่อจากการเลื่อนลง 'บัญชี' เลือกบัญชีที่มีแอพที่คุณมีคีย์ API สำหรับและตรวจสอบให้แน่ใจว่าได้เลือก read:key และ write:key สร้างโทเค็นและใช้ค่าเป็น CONTROL_KEY
COSMOSDB ใช้สำหรับการจัดเก็บข้อมูลสำหรับแอพนี้ หากต้องการรับบัญชี Azure และสร้างทรัพยากร CosmoSDB ให้ทำตามขั้นตอนในการสอนการตั้งค่าของ Azure คุณควรตั้งค่า COSMOS_ENDPOINT ให้เป็น URI ที่ให้ไว้ในบัญชีย่อยใหม่ของคุณ COSMOS_KEY เป็นคีย์หลักสำหรับบัญชี CosmoSDB ซึ่งคุณสามารถเข้าถึงได้ตามที่ Azure อธิบายไว้
COSMOS_DATABASE_ID เป็นชื่อของคอนเทนเนอร์ที่คุณจะใช้ในบัญชี COSMOSDB ของคุณ
การใช้บัญชี Azure เดียวกันที่สร้างขึ้นสำหรับ CosmoSDB สร้างคอนเทนเนอร์ที่เก็บข้อมูลใหม่ เมื่อคุณมีการตั้งค่าแล้วให้ไปที่ส่วน 'Access Keys' ในแถบด้านข้างเพื่อรับ connection string สำหรับ AZURE_STORAGE_CONNECTION_STRING จากนั้นตั้งค่า AZURE_STORAGE_CONTAINER_NAME เป็นสิ่งที่คุณตั้งชื่อคอนเทนเนอร์
หากคุณต้องการรวม Auth0 เป็นวิธีการรับรองความถูกต้องคุณจะต้องสร้างบัญชี Auth0 เมื่อคุณมีบัญชี Auth0 ให้สร้างแอปพลิเคชันด้วย 'เว็บแอปพลิเคชันปกติ' ที่เลือกเป็นประเภทแอปพลิเคชัน ในแอพนั้นคุณสามารถคัดลอกโดเมนสำหรับ AUTH0_DOMAIN และ clientId สำหรับ AUTH0_CLIENTID AUTH0_REDIRECT_URI ควรชี้ไปที่ URI ที่เหมาะสมที่ Auth0 หลังจากตรวจสอบสิทธิ์ผู้ใช้ควรเปลี่ยนเส้นทางไป ค่าเริ่มต้นควรทำงานสำหรับการทำงานในเครื่อง
บนแท็บการตั้งค่าของแอพ Auth0 ของคุณเลื่อนลงไปที่ส่วนที่เรียกว่า 'Application Uris' ในนั้นคุณควรเห็นฟิลด์สำหรับ 'URL การโทรกลับที่อนุญาต' และ 'URL ออกจากระบบที่ได้รับอนุญาต' สำหรับบริบทการไหลของหน้าเว็บโดยใช้ Auth0 คือ:
ไซต์ของคุณเชื่อมโยงผู้ใช้ไปยังหน้าเข้าสู่ระบบของแอป Auth0 ของคุณซึ่งพวกเขาลงชื่อเข้าใช้ในหน้า auth0 จะเปลี่ยนเส้นทางผู้ใช้กลับไปที่หน้า 'โทรกลับ' ของเว็บไซต์ของคุณเมื่อผู้ใช้ต้องการออกจากระบบพวกเขาจะถูกส่งไปยังหน้า Logout ของแอป Auth0
เพื่อหลีกเลี่ยงการใช้ในทางที่ผิดและการละเมิดที่อาจเกิดขึ้นคุณต้องระบุสิ่งที่ URL Auth0 สามารถเปลี่ยนเส้นทางได้ เมื่อโฮสต์แอพแชทนี้ในพื้นที่จะโฮสต์บน LocalHost: 8080 ดังนั้นตั้งค่า URL การโทรกลับที่อนุญาตเป็น 'http: // localhost: 8080/auth0-landing' เมื่อผู้ใช้ออกจากระบบเราจะให้ผู้ใช้เปลี่ยนเส้นทางกลับไปที่หน้าหลักของเราดังนั้นตั้งค่า URL ออกจากระบบที่อนุญาตเป็น 'http: // localhost: 8080/'
แอพแชทประกอบด้วยสิ่งต่อไปนี้:
Archive API เพื่อรับกิจกรรมจากเครื่องปฏิกรณ์ด้วยตนเองและรักษาประวัติการแชทChat Archive แอปพลิเคชัน React เป็นแอปพลิเคชันหน้าเดียวเริ่มต้น มันใช้ส่วนผสมของ react-router-dom และ AppProvider ที่กำหนดเองเพื่อให้บริบทความปลอดภัยสำหรับแอปพลิเคชัน
แอพใช้ @Ably-LABS/React-Hooks เพื่อโต้ตอบกับ ช่องทางที่สามารถใช้งานได้ และแอปพลิเคชันประกอบด้วย ส่วนประกอบการทำงาน ที่ทันสมัย
Snowpack เป็นเซิร์ฟเวอร์การพัฒนาซึ่งจะสร้างรหัส ES6 อย่างโปร่งใสสำหรับการผลิต
BFF เป็น API เฉพาะแอปพลิเคชัน ที่มีตรรกะเซิร์ฟเวอร์ทั้งหมดสำหรับแอพแชท เนื่องจากเป็นโฮสต์บน แอพพลิเคชั่นเว็บ Azure Static เราจึงสามารถใช้ azure-functions-core-tools ที่เรียกใช้เซิร์ฟเวอร์ API
นอกจากนี้ Runtime Azure Static Web Runtime จะ เป็นเจ้าภาพ APIs สำหรับเรา - ดังนั้นเราไม่จำเป็นต้องกังวลเกี่ยวกับการกำหนดค่าโฮสติ้ง BFF ดำเนินการบน 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 "
} ถัดไปคุณจะต้องสร้าง API 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 จะตรวจจับรหัสของคุณโดยอัตโนมัติเมื่อคุณเปลี่ยนและสร้างฟังก์ชั่นใหม่ให้คุณ
แอพใช้การรับรองความถูกต้องของโทเค็น JWT ระหว่างเว็บแอปพลิเคชันและ BFF เราจัดเก็บข้อมูลประจำตัวของผู้ใช้และเค็มด้วยวิธีหนึ่งผ่านแฮชช์ (ทำด้วย bcrypt) ในฐานข้อมูล CosmoSDB
เมื่อผู้ใช้รับรองความถูกต้องแอปจะลงนามในโทเค็น JWT พร้อมรหัสผู้ใช้และชื่อผู้ใช้ที่ส่งไปยัง BFF ในการร้องขอข้อมูลที่ได้รับการรับรองความถูกต้อง ซึ่งหมายความว่าด้วยรหัสจำนวนเล็กน้อยใน API เราสามารถมั่นใจได้ว่าผู้ใช้คือสิ่งที่พวกเขาอ้างว่าเป็นและพวกเขามีสิทธิ์เข้าถึงข้อมูล API
เราสามารถขยายโมเดลนี้เพื่อรวมการรวบรวม roles สำหรับการรับรองความถูกต้องตามการอ้างสิทธิ์ในทรัพยากรในแอปพลิเคชัน
Authenticated User Only เราสามารถสร้างการโทร API ที่ผ่านการรับรองความถูกต้องของ JWT token โดยใช้วิธีการสะดวกต่อไปนี้ใน BFF 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 หากผู้ใช้ได้รับการรับรองความถูกต้อง (พร้อมกับการรับรองว่าผู้ใช้จะได้รับการรับรองความถูกต้องทั้งหมด) หากผู้ใช้ที่กำหนดไม่ได้รับการรับรองความถูกต้องพวกเขาจะถูกเปลี่ยนเส้นทางไปยังหน้าเข้าสู่ระบบในทุกกรณี
เนื่องจาก AppProvider ดูแลการรับรองความถูกต้องคุณจะต้องใช้ hooks เพื่อเข้าถึงข้อมูลผู้ใช้และเพื่อทำการโทร 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 ; ตัวอย่างข้างต้นใช้ hook useEffect เพื่อดึงช่องเมื่อส่วนประกอบติดตั้ง - คำขอ API ทำโดยใช้ api ซ์ API ซึ่งจัดทำโดย useAuth Hook
นี่เป็นวิธีเดียวที่คุณควรทำการเรียก API ไปยัง BFF จากส่วนประกอบเนื่องจากจะทำให้แน่ใจว่าโทเค็น JWT นั้นถูกต้องและมีอยู่
หากคุณกำลังเพิ่ม 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 ) เพื่อโหลดและบันทึกเอนทิตีเหล่านี้
สำหรับการพัฒนาในท้องถิ่นคุณสามารถใช้ COSMOS เวอร์ชันโฮสต์คลาวด์หรือใช้หนึ่งใน docker container images ที่มีอยู่เพื่อเรียกใช้สำเนาฐานข้อมูลท้องถิ่น
เรากำลังใช้ Ably channels จัดเก็บข้อความแชทของเราและผลักดันกิจกรรมไปยังแอปพลิเคชัน React ของเรา ผู้ใช้ที่เชื่อมต่อแต่ละคนจะได้รับข้อความสำหรับช่องทางที่พวกเขากำลังดูอย่างแข็งขันในเวลาจริงและเรากำลังใช้ Channel rewind เพื่อเติมข้อความที่ส่งล่าสุด
ข้อความอาจได้ corrected แบบอะซิงโครไนซ์หลังจากได้รับ - ตัวอย่างเช่นเพื่อใช้การกรองคำหยาบคายหรือเพื่อแก้ไขข้อผิดพลาดในการสะกดคำ ข้อความการแก้ไขเหล่านี้จะเป็นส่วนหนึ่งของสตรีมและนำไปใช้ย้อนหลังในแอปพลิเคชัน React (การพัฒนาเพิ่มเติมเกี่ยวกับเรื่องนี้ในมหากาพย์ในภายหลัง)
การออกแบบนี้ช่วยให้เราสามารถยืน API พิเศษที่ใช้กิจกรรมเหล่านี้และเผยแพร่รายละเอียดของตนเองในช่องทางสำหรับลูกค้าในการตอบสนอง
เนื่องจากเหตุการณ์ ABLY จะหายไปเมื่อเวลาผ่านไปเราจะจัดเก็บสำเนาเหตุการณ์ขาเข้าในแต่ละช่องทางลงใน Chat Archive ของเราผ่านทาง Archive API
Archive API จะได้รับข้อความเครื่องปฏิกรณ์สำหรับช่องทั้งหมดของเราและต่อท้ายกับ Azure Storage Blobs ที่เฉพาะเจาะจงของช่องทาง API จะผนวกเข้ากับไฟล์เดียวจนกว่าจะถึงขีด จำกัด ขนาด (~ 500KB) จากนั้นสร้างไฟล์ใหม่สำหรับข้อความที่ตามมา
Archive API จะเก็บรักษาบันทึกของไฟล์เก็บถาวรที่ใช้งานอยู่ในปัจจุบันใน Metadata database สำหรับแต่ละช่อง
Archive API จะสามารถอัปเดตดัชนีการค้นหาเมื่อได้รับข้อความและเก็บถาวรเพื่อเปิดเผยในภายหลังในการค้นหา
การทดสอบเขียนด้วย jest ด้วย ts-jest ที่ใช้ในการดำเนินการทดสอบ TypeScript APIS