O objetivo é criar um aplicativo de bate -papo com um conjunto completo de recursos usando em tempo real habilmente em combinação com outros serviços para armazenar, manipular e compartilhar dados.
Se você tiver alguma dúvida, idéias ou deseja contribuir, por favor, levante um problema ou entre em contato conosco.
Nó 16 instalado
O Azure funciona tempo de execução do NPM. Para instalar esta execução:
npm install -g azure-functions-core-tools@4
um arquivo .env em ./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 serverComo visto no arquivo .env, existem alguns serviços que você precisará se inscrever para usar o projeto em seu formulário atual.
Para obter as credenciais habilmente, você precisará primeiro se inscrever para uma conta habilmente habilmente gratuita. Depois de ter uma conta habilmente, você pode acessar o aplicativo padrão gerado e obter a chave da API root. Isso será usado para o ambiente ABLY_API_KEY . A variável APP_ID ENV deve ser definida para a primeira parte da sua chave de API, antes do Fullstop. Se a sua chave da API for 12345.jh40fj23jkd0-,32c3-j- , você deve defini-lo como 12345 .
Para o CONTROL_KEY , usado para controlar a criação de chaves da API, aplicativos e, mais programaticamente, você precisará ir ao token de acesso como um usuário registrado e clique em 'Criar novo token de acesso'. Dê um nome, a partir da suspensão 'Conta', selecione a conta que possui o aplicativo para o qual você possui uma chave da API e selecione a read:key e write:key . Crie o token e use seu valor como CONTROL_KEY .
O CosmosDB é usado para armazenar dados para este aplicativo. Para obter uma conta do Azure e criar um recurso CosmosDB, siga as etapas no tutorial de configuração do Azure. Você deve definir o COSMOS_ENDPOINT como o URI fornecido em sua nova subconta. O COSMOS_KEY é a chave primária da conta CosmosDB, que você pode acessar conforme descrito pelo Azure.
COSMOS_DATABASE_ID é o nome do contêiner que você usará na sua conta CosmosDB.
Usando a mesma conta do Azure criada para o COSMOSDB, crie um novo contêiner de armazenamento de dados. Depois de ter essa configuração, vá para a seção 'Chaves de acesso' na barra lateral para obter uma connection string para AZURE_STORAGE_CONNECTION_STRING e, em seguida, defina AZURE_STORAGE_CONTAINER_NAME para o que você nomeou o contêiner.
Se você deseja incluir o Auth0 como um método de autenticação, precisará criar uma conta auth0. Depois de ter uma conta AUTH0, crie um aplicativo com 'aplicativos da Web regular' selecionados como o tipo de aplicativo. Nesse aplicativo, você pode copiar o domínio para AUTH0_DOMAIN e o cliente para o AUTH0_CLIENTID . O autenticar o URI AUTH0_REDIRECT_URI , após a autenticar um usuário. O valor padrão deve funcionar para executar localmente.
Na guia Configurações do seu aplicativo Auth0, role para baixo até a seção chamada 'URIS do aplicativo'. Nele, você deve ver um campo para 'URLs de retorno de chamada permitidos' e 'URLs de logout permitidos'. Para contexto, o fluxo de uma página da web usando auth0 é:
Seu site vincula um usuário à página de login do seu aplicativo Auth0, onde eles assinam a página Auth0 redireciona o usuário de volta para a página de “retorno de chamada 'do seu site quando o usuário deseja fazer login, eles são direcionados para a página de logout do aplicativo Auth0 e depois redirecionados de volta à página especificada no' return to Query Passed para a página de logout
Para evitar usuários e abusos em potencial, você precisa especificar o que os URLs auth0 podem redirecionar. Ao hospedar esse aplicativo de bate-papo localmente, ele está hospedado no localhost: 8080, então defina os URLs de retorno de chamada permitidos para 'http: // localhost: 8080/auth0-landing'. Quando um usuário fizer o login, teremos o usuário redirecionado de volta para a nossa página principal, então defina os URLs de logout permitidos para 'http: // localhost: 8080/'.
O aplicativo de bate -papo é composto pelo seguinte:
Archive API para receber eventos de reator habilmente e manter um histórico de bate -papoChat Archive . O aplicativo REACT é um aplicativo de página padrão padrão. Ele usa uma mistura de react-router-dom e um AppProvider personalizado para fornecer o contexto de segurança para o aplicativo.
O aplicativo usa @gancho de labirinto/react habilmente para interagir com canais habilmente , e o aplicativo é composto por componentes funcionais do React Modern.
O Snowpack é o servidor de desenvolvimento, que criará o código ES6 de forma transparente para produção.
O BFF é uma API específica do aplicativo que contém toda a lógica do servidor para o aplicativo de bate -papo. Como está hospedado em aplicativos da Web estática do Azure , podemos usar o azure-functions-core-tools executar o servidor API.
Além disso, o tempo de execução do Azure Static Web Apps host automaticamente as APIs para nós - por isso não precisamos nos preocupar em configurar a hospedagem. A melhor amiga é executada em infraestrucutre sem servidor, e o Azure SWA a escalará automaticamente para atender à demanda.
Para adicionar novos pontos de extremidade da API, você precisará adicionar um novo diretório à pasta api .
Primeiro, crie um diretório para a nova API - por exemplo, api/messages . Em seguida, crie um arquivo function.json no novo diretório.
{
"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 "
} Em seguida, você precisará criar sua 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" } ;
} Esta API agora será montada em http://localhost:8080/api/messages .
E é isso! A ferramenta e o SDK detectarão automaticamente seu código à medida que você o alterará e reconstruirá suas funções para você.
O aplicativo usa a autenticação de token JWT entre o aplicativo da Web e a BFF. Armazenamos credenciais de usuário e saldos de uma maneira de fazer senhas (feitas com o BCRYPT) no banco de dados CosmosDB.
Quando um usuário autentica, o aplicativo assina um token JWT com o ID e o nome de usuário do usuário que são enviados para a melhor amiga nas solicitações subsequentes de dados autenticados. Isso significa que, com uma pequena quantidade de código nas APIs, podemos garantir que o usuário seja quem eles afirmam ser e que eles têm o direito de acessar dados da API.
Podemos expandir esse modelo para incluir uma coleção de roles para autenticação baseada em reivindicações aos recursos no aplicativo.
Authenticated User Only Podemos criar uma chamada de API autenticada JWT token usando os seguintes métodos de conveniência na 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" )
} ;
} ) ;
}Se você deseja acessar as informações autenticadas dos usuários como parte de uma dessas chamadas de API, você pode fazer o seguinte:
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
} A autenticação no aplicativo é implementada em AppProviders.jsx .
Ele fornece um gancho do React que retornará o objeto userDetails se o usuário for autenticado (além de garantir que o usuário seja autenticado). Se um determinado usuário não for autenticado, ele será redirecionado para a página de login em todos os casos.
Como o AppProvider cuida da autenticação, você precisará usar ganchos para acessar os dados do usuário e fazer chamadas de API autenticadas em qualquer componente.
Aqui está um exemplo de acesso ao objeto userDetails do usuário atualmente autenticado.
import { useAuth } from "../../AppProviders" ;
const MyComponent = ( ) => {
const { user } = useAuth ( ) ;
return < div > { user . username } </ div > ;
} ;
export default MyComponent ; Você também pode acessar uma instância da classe BffApiClient , que permitirá que você faça chamadas de API autenticadas e já contém o JWT token de Usuários atualmente registrado.
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 ; O exemplo acima usa o gancho useEffect para buscar os canais quando o componente é montado - a solicitação da API é feita usando a instância api , fornecida pelo gancho useAuth .
Esta é a única maneira de fazer chamadas API para a melhor amiga a partir de um componente, pois garantirá que o token JWT seja válido e presente.
Se você estiver adicionando novas BFF APIs ao aplicativo, precisará implementar uma nova função em /app/src/sdk/BffApiClient.js para disponibilizá -la para seus componentes.
Essas chamadas de BffApiClient são simples e se parecem com a seguinte:
async listChannels ( ) {
const result = await this . get ( "/api/channels" ) ;
return await result . json ( ) ;
} Algum código de utilidade no cliente garantirá que o JWT token correto esteja presente quando a solicitação for feita.
Estamos usando o COSmosDB para armazenar nossos metadados do aplicativo, porque é um banco de dados gerenciado e escalável e altamente disponível que não precisamos nos administrar. Ele pode ser executado em um modo pré-provisionado ou sem servidor, ajudando a manter os custos baixos quando o aplicativo não estiver em uso (ao custo de algum desempenho).
Utilizamos um único banco de dados CosmosDB para armazenar todos os metadados e, dentro, criamos uma coleção para cada tipo de entidade que estamos armazenando.
Por exemplo: a coleção User , armazena nossos registros de usuário - e pode ser consultado usando a sintaxe do tipo SQL. O CosmosDB facilita a indexação automática de documentos JSON.
Cada uma das entidades de metadados armazenados possui um campo de id e um type , e estamos usando uma classe generic repository ( /api/common/dataaccess/CosmosDbMetadataRepository ) para carregar e salvar essas entidades.
Para o desenvolvimento local, você pode usar a versão hospedada em nuvem do Cosmos ou usar uma das docker container images para executar uma cópia local do banco de dados.
Estamos usando Ably channels para armazenar nossas mensagens de bate -papo e empurrar eventos para o nosso aplicativo React. Cada usuário conectado receberá mensagens para canais que eles estão visualizando ativamente em tempo real e estamos usando Channel rewind para preencher as mensagens enviadas mais recentemente.
As mensagens podem ser corrected de forma assíncrona após o recebimento - por exemplo, para aplicar a filtragem de palavrões ou para corrigir erros de ortografia. Essas mensagens de correção farão parte do fluxo e aplicadas retroativamente no aplicativo React. (Desenvolvimento adicional sobre isso em épicos posteriores)
Esse design nos permite suportar APIs extras que consomem esses eventos e publicam suas próprias elaborações nos canais para os clientes responderem.
Como os eventos habilmente desaparecerão com o tempo, armazenaremos cópias de eventos de entrada em cada canal em nosso Chat Archive através da Archive API .
A Archive API receberá mensagens do reator para todos os nossos canais e os anexará a Azure Storage Blobs específicos para canais. A API anexará a um único arquivo até atingir um limite de tamanho (~ 500kb) e, em seguida, criará um novo arquivo para mensagens subsequentes.
A Archive API manterá um registro do arquivo de arquivo ativo atualmente no Metadata database para cada canal.
A Archive API poderá atualizar um índice de pesquisa à medida que as mensagens são recebidas e arquivadas para expô -las posteriormente em pesquisa.
Os testes são escritos em jest com ts-jest usados para executar os testes TypeScript de APIs.