الهدف من ذلك هو إنشاء تطبيق دردشة مع مجموعة ميزة كاملة باستخدام الوقت الحقيقي باقتدار مع خدمات أخرى لتخزين البيانات ومعالجتها ومشاركتها.
إذا كان لديك أي أسئلة أو أفكار أو ترغب في المساهمة ، فيرجى إثارة مشكلة أو التواصل معنا.
العقدة 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 Root. سيتم استخدام هذا لبيئة 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 ، قم بإنشاء حاوية تخزين بيانات جديدة. بمجرد أن يكون لديك هذا الإعداد ، انتقل إلى قسم "مفاتيح الوصول" في الشريط الجانبي للحصول على 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 يعيد توجيه المستخدم إلى صفحة "رد الاتصال" لموقع الويب الخاص بك عندما يريد المستخدم تسجيل الخروج ، ويتم توجيههم إلى صفحة تسجيل الدخول الخاصة بتطبيق Auth0 ثم إعادة توجيهها إلى الصفحة المحددة في استعلام "الإرجاع" إلى صفحة التسجيل التي تم نقلها إلى صفحة التسجيل.
لتجنب سوء الاستخدام والإساءة المحتملة ، تحتاج إلى تحديد ما يمكن أن يعيده Auth0 عناوين URL. عند استضافة تطبيق الدردشة هذا محليًا ، يتم استضافته على LocalHost: 8080 ، لذا قم بتعيين عناوين URL للاتصال المسموح بها على "http: // localhost: 8080/auth0-llange". عند خروج المستخدم ، سنعيد توجيه المستخدم إلى صفحتنا الرئيسية ، لذا قم بتعيين عناوين URL المسموح بها إلى "http: // localhost: 8080/'.
تطبيق الدردشة يتكون من ما يلي:
Archive API لتلقي الأحداث من مفاعل Austly والحفاظ على تاريخ الدردشةChat Archive . تطبيق React هو تطبيق افتراضي ، صفحة واحدة. يستخدم مزيجًا من react-router-dom و AppProvider مخصص لتوفير سياق الأمان للتطبيق.
يستخدم التطبيق @aply-labs/react-hooks للتفاعل مع قنوات ببراعة ، ويتكون التطبيق من مكونات وظيفية للتفاعل الحديثة.
Snowpack هو خادم التطوير ، والذي سيقوم بإنشاء رمز ES6 بشكل شفافي للإنتاج.
BFF هو واجهة برمجة تطبيقات محددة للتطبيق تحتوي على جميع منطق Serverside لتطبيق الدردشة. نظرًا لأنه يتم استضافته على تطبيقات Azure Static Web ، يمكننا استخدام azure-functions-core-tools API.
بالإضافة إلى ذلك ، فإن وقت تشغيل Azure Static Web Apps يستضيف واجهات برمجة التطبيقات - لذلك لا داعي للقلق بشأن تكوين الاستضافة. يتم تنفيذ BFF على Serverless Infristrucutre ، وسيقوم 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" } ;
} سيتم الآن تثبيت واجهة برمجة التطبيقات هذه على http://localhost:8080/api/messages .
وهذا كل شيء! ستقوم الأدوات و SDK بإزالة الكود الخاص بك أثناء تغييره وإعادة بناء وظائفك لك.
يستخدم التطبيق مصادقة الرمز المميز JWT بين تطبيق الويب و BFF. نقوم بتخزين بيانات اعتماد المستخدم والمملح ، إحدى كلمات المرور ذات التجزئة (التي يتم مع BCrypt) في قاعدة بيانات CosmosDB.
عندما يقوم المستخدم بتوثيق ، يوقع التطبيق رمزًا JWT مع معرف المستخدم واسم المستخدم الذي يتم إرساله بعد ذلك إلى BFF في الطلبات اللاحقة للبيانات المصادقة. هذا يعني ، مع وجود كمية صغيرة من التعليمات البرمجية في واجهات برمجة التطبيقات ، يمكننا التأكد من أن المستخدم هو من يدعي أنه ، وأن يحق لهم الوصول إلى بيانات API.
يمكننا توسيع هذا النموذج ليشمل مجموعة من roles للمصادقة القائمة على المطالبات للموارد في التطبيق.
Authenticated User Only مكالمة API يمكننا إنشاء مكالمة 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 يهتم بالمصادقة ، فستحتاج إلى استخدام السنانير للوصول إلى بيانات المستخدم ، ولإجراء مكالمات 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 باستخدام مثيل api ، الذي يوفره خطاف useAuth .
هذه هي الطريقة الوحيدة التي يجب عليك بها إجراء مكالمات API إلى BFF من مكون ، حيث ستضمن أن رمز JWT صالح وحاضر.
إذا كنت تضيف BFF APIs جديدة إلى التطبيق ، فستحتاج إلى تنفيذ وظيفة جديدة في /app/src/sdk/BffApiClient.js 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. (مزيد من التطوير في هذا في الملاحم اللاحقة)
يتيح لنا هذا التصميم الوقوف على واجهات برمجة التطبيقات الإضافية التي تستهلك هذه الأحداث ، ونشر توضيحهم على القنوات للعملاء للرد عليها.
نظرًا لأن الأحداث المتنوعة ستختفي بمرور الوقت ، فإننا سنقوم بتخزين نسخ من الأحداث الواردة على كل قناة في Chat Archive الخاص بنا عبر Archive API .
ستتلقى Archive API رسائل مفاعل لجميع قنواتنا ، وإلحاقها بالألوان الخاصة Azure Storage Blobs . سيتم إلحاق واجهة برمجة التطبيقات بملف واحد حتى يصل إلى حد الحجم (حوالي 500 كيلو بايت) ثم إنشاء ملف جديد للرسائل اللاحقة.
ستحافظ Archive API على سجل لملف الأرشيف النشط حاليًا في Metadata database لكل قناة.
ستتمكن Archive API من تحديث فهرس البحث حيث يتم استلام الرسائل ويرشى لفضحها لاحقًا في البحث.
تتم كتابة الاختبارات في jest مع ts-jest المستخدمة لتنفيذ اختبارات TypeScript .