Há alguns anos, Brett Lawson fez uma ótima série de blogs sobre o uso do Couchbase Server e do Node.js para o desenvolvimento de uma estrutura de servidor de jogos. Desde então, o SDK do Node.js para o Couchbase cresceu significativamente da versão 1.x para a 2.x.

Neste artigo, vamos revisitar essas três postagens originais e alterá-las para que fiquem em dia com os padrões mais recentes do Node.js e do Express Framework, bem como com a versão mais recente do Node.js SDK do Couchbase.

Os pré-requisitos

  • Node.js 0.12
  • Servidor Couchbase 4.0

Preparação do projeto

Quer você esteja no Mac, no Windows ou no Linux, a criação de um novo aplicativo do Express Framework deve ser consistente entre eles. Crie um novo diretório chamado gameapi-nodejs provavelmente em sua área de trabalho e, no Terminal (Mac/Linux) ou no Prompt de Comando (Windows), execute o seguinte comando:

Responda às perguntas feitas da melhor forma possível. Obviamente, o diretório do projeto deve ser seu diretório atual no prompt de comando ou no terminal para que isso seja bem-sucedido. Como alternativa ao comando, você pode criar e preencher esse arquivo manualmente. Crie um novo arquivo chamado package.json no diretório do seu projeto e preencha-o com o seguinte:

Ainda não terminamos. Precisamos instalar as dependências do projeto antes de começarmos a planejar o aplicativo. No prompt de comando ou no terminal, execute o seguinte comando:

Isso instalará o Express Framework, o SDK do Couchbase Node.js, o Forge para hashing de senha, o UUID para gerar valores exclusivos e o middleware body-parser para lidar com dados POST codificados por URL e JSON.

Preparando o banco de dados

Antes de começarmos a codificar, o Couchbase Server deve ser instalado com um bucket chamado amostra de jogos criado.

Como este projeto fará uso de um recurso importante do Couchbase 4.0, precisaremos configurar ainda mais o bucket para que seja criado um índice primário. Se você estiver usando uma máquina Linux, Mac ou Windows, isso pode ser feito facilmente por meio do cliente Couchbase Query (CBQ).

Mac

Para abrir o CBQ no Mac, no Terminal, execute o seguinte:

Windows

Para abrir o CBQ no Windows, no prompt de comando, execute o seguinte:

Criação de um índice primário

Com o CBQ aberto, execute o seguinte:

Seu balde agora está pronto para ser usado com o restante do projeto!

A estrutura do projeto

Nosso projeto será composto do seguinte:

Item Pais Descrição
modelos Todos os arquivos de classe do banco de dados serão colocados aqui
rotas Todas as definições de pontos de extremidade da API serão colocadas aqui
accountmodel.js modelos Criação e recuperação de informações de conta
sessionmodel.js modelos Autenticação de usuários e manutenção das informações da sessão
statemodel.js modelos Criar, atualizar e recuperar informações sobre o estado do jogo
rotas.js rotas Todos os pontos de extremidade para GET, POST, PUT estarão aqui
app.js Informações de configuração do servidor
config.json Variáveis estáticas
package.json Informações de dependência

O básico

Antes de nos aprofundarmos na lógica do servidor de jogos do Node.js, é melhor configurar o aplicativo básico do Express Framework.

Na raiz do projeto, crie e abra um arquivo chamado config.json pois ele conterá informações estáticas, como as informações de conectividade do Couchbase. Inclua o seguinte quando ele estiver aberto:

Na raiz do projeto, crie e abra um arquivo chamado app.js pois ele conterá todas as informações básicas sobre a execução do servidor Node.js. Inclua o seguinte quando abrir o arquivo:

Vamos detalhar o que vemos aqui. As primeiras linhas são a inclusão das dependências em nosso aplicativo. Não há nada de especial nisso. O que é importante é o seguinte:

Isso significa que analisaremos os dados JSON e os dados codificados por URL dos corpos das solicitações. Em particular, solicitações POST e PUT. A próxima coisa que faremos é inicializar o cluster do Couchbase no aplicativo e abrir um único bucket para uso no aplicativo:

Ao incluir module.exports.bucket estamos dizendo que vamos usá-lo por meio do aplicativo. Agora, em outros arquivos JavaScript, se quisermos acessar o bucket, basta fazer isso:

Em seguida, você verá que incluímos nosso rotas/routes.js e passando a ele o arquivo aplicativo como um dos argumentos. O que isso faz será óbvio em breve.

Por fim, ao chamar app.listen estamos dizendo ao Node.js para escutar solicitações na porta 3000. O aplicativo está quase utilizável em seu estado mais básico. Criar e abrir rotas/routes.js e adicione as seguintes linhas:

Agora, o aplicativo pode ser executado com a execução de nó app.js no prompt de comando ou no terminal. Aterrissando em http://localhost:3000 deve lhe dar a mensagem "Not a valid endpoint" (Não é um endpoint válido).

O modelo de dados da API

Antes de mergulhar no código que interessa, é melhor saber como os dados ficarão no Couchbase. Para qualquer usuário, haverá quatro documentos com a seguinte aparência:

O documento do usuário

O documento do usuário conterá todas as informações sobre um usuário. Para este aplicativo, essas informações serão um nome, um nome de usuário e uma senha.
O nome desse documento será prefixado com usuário:: e ter um valor uid exclusivo anexado a ele. Essa estratégia de nomeação de documentos usa o que é chamado de chaves compostas.

O documento de nome de usuário

O documento de nome de usuário conterá apenas o valor uid encontrado no documento de usuário. A finalidade do documento de nome de usuário pode ser considerada como um documento de método de login. Por exemplo, ele poderia representar um login simples em que o usuário digita um nome de usuário e uma senha. Como o documento contém o uid de vinculação, ele pode ser vinculado ao documento do usuário. O documento de nome de usuário é prefixado com nome de usuário:: e o nome de usuário real é anexado a ele. Uma estratégia semelhante pode ser usada se estiver usando o Facebook ou o Twitter como métodos de login e vinculando-os também por meio do campo uid.

O documento da sessão

O documento de sessão é um documento com expiração automática que atua como uma rota do usuário para informações mais seguras. Em teoria, o front-end do usuário armazenará o valor sid e o transmitirá entre os pontos de extremidade protegidos. Com ele, um uid vinculado a um usuário pode ser acessado.

O documento do Estado

O documento de estado conterá informações sobre o estado específico do jogo. Por exemplo, se o personagem do jogo tiver cinco vidas restantes e vinte poções, essas informações serão salvas aqui. Há informações de versão para evitar que conflitos entre duas sessões de jogo ativas sejam salvos na mesma conta.

Criação do modelo de conta

O modelo de conta servirá a três propósitos específicos:

  • Criação de uma conta de usuário
  • Recuperação de uma conta de usuário
  • Comparação de uma senha com hash com uma senha sem hash

Antes de começarmos a codificar, precisamos colocar nossos includes em ordem. Adicione o seguinte ao topo do arquivo models/accountmodel.js file:

Com base no modelo de dados visto acima, a criação de uma conta de usuário exigirá um nome, um nome de usuário e uma senha. Com essas informações em mãos, a senha será transformada em hash e as informações do usuário serão armazenadas ao lado de um documento de referência da seguinte forma:

Observe que no código acima, primeiro tentamos inserir um novo documento de referência. Se houver falha (talvez ele já exista), nenhum dos documentos será salvo e, em vez disso, a mensagem de erro será retornada. Independentemente de ser um sucesso ou uma falha, o retorno de chamada do arquivo de rotas é executado para exibir qualquer tipo de resposta ao solicitante.

Em termos de leitura de dados do usuário, uma das duas coisas pode acontecer. Poderíamos passar um nome de usuário, porque estamos fazendo um login simples, ou poderíamos passar um ID de usuário. Depende do que estamos buscando. Digamos que estejamos apenas fazendo login com o nome de usuário, você provavelmente desejaria chamar uma função como esta:

Observe como estamos usando uma consulta N1QL, nova no Couchbase 4.0. Ela é muito semelhante ao SQL tradicional e também nos dá a conveniência de não precisarmos processar ou formatar dados na camada do aplicativo. O Couchbase Server fará tudo isso por nós. No entanto, temos a opção de solicitar dados como nas versões mais antigas do Couchbase e em outras plataformas NoSQL.

Na instrução N1QL acima, estamos selecionando um documento com a chave composta anexada ao nosso nome de usuário em texto simples. Está ocorrendo uma união com a propriedade uid do documento usernames (chave externa) e o documento users (chave primária).

Isso nos leva à validação de uma senha. Não há chamadas ao banco de dados aqui. Simplesmente pegaremos uma senha bruta, faremos o hash dela e, em seguida, compararemos o hash com a senha armazenada.

Para fazer models/accountmodel.js utilizável em nosso arquivo de rotas, devemos exportá-lo da seguinte forma na parte inferior do arquivo
models/accountmodel.js código:

Criação do modelo de sessão

O modelo de sessão servirá a três propósitos específicos:

  • Criação de uma sessão de usuário
  • Recuperação de uma sessão de usuário
  • Validação de uma sessão de usuário

Antes de começarmos a codificar, precisamos colocar nossos includes em ordem. Adicione o seguinte ao topo do arquivo models/sessionmodel.js file:

Criação de uma sessão

Quando um usuário deseja criar uma sessão, é necessário fornecer um uid. Com isso em mãos, um ID de sessão exclusivo é criado e inserido no banco de dados com uma expiração. Quando o documento expirar, ele será automaticamente removido do Couchbase sem nenhuma intervenção do usuário, fazendo assim o logout do usuário.

Autenticação de um usuário

Com a sessão de usuário criada, o ID da sessão deve ser usado sempre que o usuário quiser acessar um endpoint protegido.

No código acima, a função receberá um ID de sessão que será usado para verificar se já existe uma sessão. Em caso afirmativo, ela redefinirá o tempo de expiração da sessão e retornará o uid associado a ela. A obtenção das informações da sessão pode ser vista da seguinte forma:

Nada mal, certo? Por fim, você pode ver que a redefinição da sessão ocorre de maneira semelhante:

O método de toque não adicionará tempo, mas sim redefinirá o tempo. Nesse caso, ele redefinirá o cronômetro para uma hora

Para fazer models/sessionmodel.js utilizável em nosso arquivo de rotas, devemos exportá-lo da seguinte forma na parte inferior do arquivo models/sessionmodel.js código:

Criação do modelo de estado

O modelo de estado servirá a dois propósitos específicos:

  • Criação ou atualização de um estado salvo
  • Recuperação de um save-state por nome

Antes de começarmos a codificar, precisamos colocar nossos includes em ordem. Adicione o seguinte ao topo do arquivo models/statemodel.js file:

Criação de um estado de salvamento

O objetivo por trás da criação ou atualização de um save-state é que primeiro verificaremos se existe um. Se não existir, nós o criaremos. Se existir, obteremos as informações existentes, as alteraremos e substituiremos as informações existentes no banco de dados. Tudo isso é feito enquanto aumentamos a versão do estado para evitar conflitos entre os salvamentos de jogos. Na verdade, não é para evitar conflitos ao salvar no Couchbase, apenas para garantir que você não pegue o jogo em dois dispositivos e substitua os dados do jogo por um salvamento muito mais antigo.

Veja o upsert lá. No Couchbase, isso significa criar, caso não exista, ou substituir, caso exista. Muito conveniente para coisas como salvar estados de um jogo.

Obtendo os estados

Isso nos permite obter qualquer estado salvo que possamos ter criado.

O conceito por trás disso é que estamos fazendo uma pesquisa de documento com base em um ID de usuário. Se o documento de estado para um determinado uid existir, faça uma pesquisa na matriz associativa para ver se o nome do estado existe. Se existir, retorne qualquer conteúdo de estado existente para o nome.

Para fazer models/statemodel.js utilizável em nosso arquivo de rotas, devemos exportá-lo da seguinte forma na parte inferior do arquivo models/statemodel.js código:

Criação das rotas de API

Criamos todos os modelos de dados necessários acima, então é hora de unir tudo isso com rotas acessíveis ao usuário. Voltando à seção rotas/routes.js começaremos adicionando as rotas do modelo de conta:

O endpoint acima espera uma solicitação POST com um parâmetro de corpo nome, nome de usuário e senha. Estamos ouvindo o POST porque é uma prática recomendada usar o POST ao criar ou inserir dados por meio de uma solicitação HTTP. Se todos os três existirem, então o AccountModel.create() é chamado e, por fim, retorna um erro ou um resultado, dependendo do sucesso do método. Se pelo menos um dos parâmetros necessários não existir, será retornado um erro. Uma lista de códigos de erro pode ser vista aqui.

Um ponto de extremidade para obter informações do usuário não é tão importante neste exemplo, portanto, iremos direto para a autenticação do usuário e a criação de uma sessão. Na seção rotas/routes.js adicione o seguinte:

O ponto de extremidade de autenticação espera um nome de usuário e uma senha. Se ambos forem encontrados, o usuário será procurado. Se o usuário for encontrado, será feita uma comparação de senhas e, se for bem-sucedida, será criada uma sessão.

Os dois últimos pontos de extremidade da API que são úteis para nós são para obter e criar estados salvos. Começando com a criação de um endpoint de estado salvo, em seu rotas/routes.jsAdicione o seguinte:

O endpoint acima espera um parâmetro de URL que representa o nome do estado, um parâmetro de consulta que representa a versão atual do estado e um corpo de solicitação que pode conter qualquer JSON imaginável, pois representa os dados do jogo que vale a pena salvar.

Por fim, resta-nos obter os estados que foram salvos.

O ponto de extremidade acima espera um parâmetro de URL que represente o estado de salvamento específico a ser encontrado. É claro que ele também espera que o usuário seja autenticado primeiro.

Testando a API

Os pontos de extremidade da API que criamos no rotas/routes.js pode ser testado de várias maneiras. Duas das minhas formas favoritas de testar são com a extensão Postman para o Chrome ou com o cURL. Experimente você mesmo usando o cURL:

Acima, fomos em frente e criamos uma nova conta de usuário

Acima, fomos em frente e criamos uma sessão de usuário. Essa mesma estratégia também pode ser aplicada aos outros endpoints.

Conclusão

Usando o Node.js e o Couchbase Server SDK, você pode criar facilmente um backend de API para seus jogos. No Couchbase 4.0, agora você tem a liberdade de usar o N1QL como uma opção para consultar dados em seu aplicativo.

O aplicativo Node.js completo sobre o qual escrevemos neste artigo pode ser baixado gratuitamente no site GitHub do Couchbase Labs repositório.

Autor

Postado por Nic Raboy, defensor dos desenvolvedores, Couchbase

Nic Raboy é um defensor das modernas tecnologias de desenvolvimento móvel e da Web. Ele tem experiência em Java, JavaScript, Golang e uma variedade de estruturas, como Angular, NativeScript e Apache Cordova. Nic escreve sobre suas experiências de desenvolvimento relacionadas a tornar o desenvolvimento móvel e da Web mais fácil de entender.

5 Comentários

  1. Martin Micunda julho 18, 2015 em 3:52 pm

    Hi,

    Você ainda precisa habilitar o N1QL no couchbase 4 executando \'bucket.enableN1ql(\'localshot:8093\');\'? Obrigado pela atenção

    1. Matt Ingenthron julho 18, 2015 em 6:12 pm

      Não, ele só funciona com o SDK mais recente

      1. Quero lhe pedir o erro de um cliente:\"

        [com.couchbase.client.deps.io.netty.util.ResourceLeakDetector] FUGA: ByteBuf.release() não foi chamado antes de ser coletado do lixo. Ative o relatório de vazamento avançado para descobrir onde ocorreu o vazamento. Para ativar o relatório de vazamento avançado, especifique a opção JVM \'-Dcom.couchbase.client.deps.io.netty.leakDetectionLevel=advanced\' ou chame ResourceLeakDetector.setLevel()\"
        Qual é o problema? Como resolvê-lo

  2. Hi,

    O N1QL só pode ser usado para consultas ou pode ser usado para fazer UPSERT\'s e INSERT\'s? Agradecimentos

    1. No momento, INSERT, UPDATE, DELETE e UPSERT são beta. Você pode usá-los, mas até que saiam da versão beta, não recomendamos usá-los em um ambiente de produção.

      http://developer.couchbase.com

      Melhor,

Deixar uma resposta