Uma das minhas tecnologias preferidas para o desenvolvimento de aplicativos da Web é o Node.js. Como desenvolvo muito em JavaScript, essa é outra peça que se encaixa no meu quebra-cabeça de desenvolvimento. Há pouco tempo, escrevi um guia para usar o Couchbase Mobile e o Couchbase Node.js SDK na mesma pilha. Naquele artigo, mencionei que há várias maneiras diferentes de realizar essa tarefa. Pensei em elaborar outra maneira de realizar o trabalho, desta vez usando PouchDB.
O PouchDB é um banco de dados JavaScript que funciona em conjunto com o Couchbase Sync Gateway e o Couchbase Server. Por ser JavaScript, você pode usá-lo em seus aplicativos baseados em navegador e no lado do servidor.
Os requisitos
Como este é um aplicativo JavaScript, não haverá muitas dependências de software. As poucas que existem são as seguintes:
- Node.js 4.0+
- Gateway de sincronização do Couchbase
Este é um aplicativo Node.js, mas o Node Package Manager (NPM) é o que fará a maior parte do trabalho pesado quando se trata de preparar nosso projeto. Ele obterá o PouchDB e as dependências restantes. Usaremos o Couchbase Sync Gateway banco de dados na memória porque este é apenas um aplicativo de exemplo. Na produção, você desejará conectar o Sync Gateway ao Couchbase Server para armazenamento persistente.
Configuração do Couchbase Sync Gateway para sincronização de dados
O Sync Gateway manipulará todos os nossos dados remotos antes e depois de chegarem ao Couchbase Server. Ele é o nosso serviço intermediário que orquestrará os dados entre plataformas, dispositivos etc. Ele não é um requisito para a criação de aplicativos Node.js que funcionem com o Couchbase Server. Estamos usando-o porque desejamos oferecer suporte à sincronização móvel também, embora isso não seja demonstrado neste exemplo.
Com o download e a instalação do Couchbase Sync Gateway, precisamos estabelecer uma configuração para carregar no tempo de execução. Crie um arquivo chamado sync-gateway-config.json e incluem o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{ "log":["CRUD+", "REST+", "Mudanças+", "Anexar+"], "bancos de dados": { "exemplo": { "servidor":"walrus:", "sync":` função (doc) { canal (doc.canais); } `, "usuários": { "CONVIDADO": { "desativado": falso, "admin_channels": ["*"] } } } }, "CORS": { "Origem": ["http://localhost:3000"], "LoginOrigin": ["http://localhost:3000"], "Headers" (Cabeçalhos): ["Content-Type"], "MaxAge": 17280000 } } |
No arquivo de configuração muito básico acima, estabelecemos um banco de dados chamado exemplo que usa a opção de armazenamento do Sync Gateway na memória. Não há permissões específicas de leitura ou gravação nessa configuração, o que significa que todos os dados existirão no mesmo canal.
Como estamos executando o Sync Gateway e nosso exemplo de Node.js a ser criado em breve no mesmo computador, mas em portas diferentes, precisamos permitir o compartilhamento de recursos entre origens (CORS). Se não o fizermos, acabaremos com erros relacionados ao JavaScript. Na configuração acima, estamos dizendo que queremos permitir a comunicação de http://localhost:3000, que é o nosso aplicativo Node.js.
Nesse ponto, o Sync Gateway pode ser executado. Em um ambiente de produção, o sistema in-memory morsa pode ser substituído pelo nome do host de um determinado cluster do Couchbase Server.
Desenvolvimento do aplicativo da Web Node.js
Para facilitar a compreensão, vamos criar um aplicativo Node.js novo e trabalhar em seu desenvolvimento. Isso pode ser feito usando o Node Package Manager.
No prompt de comando ou no terminal, execute o seguinte:
1 |
npm inicial --y |
O comando acima criará um arquivo package.json que manterá todas as dependências do nosso projeto. Com o arquivo package.json no lugar, vamos obter algumas dependências:
1 |
npm instalar expresso corpo-analisador bolsadb --salvar |
O comando acima instalará o Express Framework, um pacote necessário para tratar os dados do corpo nas solicitações, e o PouchDB para gerenciar os dados do nosso aplicativo.
Antes de começarmos a escrever o código, precisamos criar um arquivo chamado app.js que conterá toda a lógica do nosso aplicativo.
Inicialização da API RESTful
Com o app.js criado, abra-o e inclua o seguinte código JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
var Expresso = exigir("expresso"); var Analisador de corpo = exigir("body-parser"); var PouchDB = exigir("pouchdb"); var aplicativo = Expresso(); aplicativo.uso(Analisador de corpo.json()); aplicativo.uso(Analisador de corpo.codificado por url({ estendido: verdadeiro })); var banco de dados = novo PouchDB("http://192.168.57.1:4984/example"); aplicativo.obter("/people", função(req, res) { }); aplicativo.obter("/people/:id", função(req, res) { }); aplicativo.postagem("/people", função(req, res) { }); aplicativo.excluir("/people", função(req, res) { }); var servidor = aplicativo.ouvir(3000, função() { banco de dados.informações().então(função(informações) { console.registro(informações); console.registro("Escutando na porta %s...", servidor.endereço().porto); }); }); |
Então, o que está acontecendo no código acima? Em primeiro lugar, estamos importando as dependências que foram instaladas anteriormente e as estamos inicializando.
Como este é um aplicativo do lado do servidor, temos duas opções quando se trata de usar o PouchDB. Podemos criar um banco de dados local em nosso servidor de aplicativos que sincroniza com o Sync Gateway ou podemos nos conectar diretamente à instância do Sync Gateway.
1 |
var banco de dados = novo PouchDB("http://192.168.57.1:4984/example"); |
A informação acima indica que vamos nos conectar diretamente ao nosso servidor Sync Gateway em execução local. Você pode escolher a opção de sincronização se quiser adotar uma abordagem diferente no balanceamento de carga.
1 2 3 4 |
aplicativo.obter("/people", função(req, res) { }); aplicativo.obter("/people/:id", função(req, res) { }); aplicativo.postagem("/people", função(req, res) { }); aplicativo.excluir("/people", função(req, res) { }); |
Estaremos criando uma API RESTful que usa CRUD, mas, por enquanto, faz sentido apenas definir cada um dos pontos de extremidade que desejamos usar no Express Framework.
Por fim, definimos como queremos atender ao aplicativo:
1 2 3 4 5 6 |
var servidor = aplicativo.ouvir(3000, função() { banco de dados.informações().então(função(informações) { console.registro(informações); console.registro("Escutando na porta %s...", servidor.endereço().porto); }); }); |
Vamos servir o aplicativo em http://localhost:3000 e, quando o servidor for inicializado, imprimiremos informações sobre o PouchDB. Isso nos ajudará a ter uma ideia sobre a conexão e os dados existentes.
Incluindo a lógica de manipulação de dados do PouchDB
Com o aplicativo inicializado, podemos começar a aplicar a lógica do aplicativo a cada um dos métodos de endpoint. Começando com o endpoint de lista, temos o seguinte:
1 2 3 4 5 6 7 8 9 |
aplicativo.obter("/people", função(req, res) { banco de dados.todos os documentos({incluir_docs: verdadeiro}).então(função(resultado) { res.enviar(resultado.linhas.mapa(função(item) { retorno item.doc; })); }, função(erro) { res.status(400).enviar(erro); }); }); |
Quando o ponto de extremidade for atingido, consultaremos todos os documentos e incluiremos as propriedades do documento nos resultados. Para ignorar as informações que podem não ser úteis para nós, podemos mapear a resposta antes de retorná-la; caso contrário, podemos retornar um erro.
Em vez de listar todos os documentos, talvez queiramos obter um único documento.
1 2 3 4 5 6 7 8 9 10 |
aplicativo.obter("/people/:id", função(req, res) { se(!req.parâmetros.id) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `id`"}); } banco de dados.obter(req.parâmetros.id).então(função(resultado) { res.enviar(resultado); }, função(erro) { res.status(400).enviar(erro); }); }); |
No cenário acima, esperamos que um ID de documento seja incluído na solicitação. Se o ID existir, tentaremos obter um documento e devolvê-lo ao solicitante; caso contrário, retornaremos um erro.
Que tal criar novos documentos?
Para criar documentos dentro do Couchbase, faríamos algo como o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 |
aplicativo.postagem("/people", função(req, res) { se(!req.corpo.primeiro nome) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `firstname`"}); } mais se(!req.corpo.sobrenome) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `sobrenome`"}); } banco de dados.postagem(req.corpo).então(função(resultado) { res.enviar(resultado); }, função(erro) { res.status(400).enviar(erro); }); }); |
No código acima, estamos esperando um primeiro nome
e um sobrenome
para existir. Se isso for verdade, criaremos o documento usando todo o corpo da postagem e retornaremos a resposta. Não é necessário usar todo o corpo da postagem, mas neste exemplo estamos usando. Observe que isso só criará um documento, não o atualizará. A atualização dos documentos usaria um colocar
em vez de um método postagem
método.
A parte final do nosso aplicativo é o endpoint para exclusão de dados.
1 2 3 4 5 6 7 8 9 10 11 12 |
aplicativo.excluir("/people", função(req, res) { se(!req.corpo.id) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `id`"}); } banco de dados.obter(req.corpo.id).então(função(resultado) { retorno banco de dados.remover(resultado); }).então(função(resultado) { res.enviar(resultado); }, função(erro) { res.status(400).enviar(erro); }); }); |
Esperamos que um ID seja passado na solicitação. Se esse ID existir, primeiro fazemos uma pesquisa para garantir que o documento exista. Se o documento existir, podemos excluí-lo. Tudo isso foi realizado com o encadeamento de promessas JavaScript.
Experimentando o código-fonte do projeto finalizado
Se você quiser ter uma visão mais clara da aparência desse aplicativo, o código completo pode ser visto abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
var Expresso = exigir("expresso"); var Analisador de corpo = exigir("body-parser"); var PouchDB = exigir("pouchdb"); var aplicativo = Expresso(); aplicativo.uso(Analisador de corpo.json()); aplicativo.uso(Analisador de corpo.codificado por url({ estendido: verdadeiro })); var banco de dados = novo PouchDB("http://192.168.57.1:4984/example"); aplicativo.obter("/people", função(req, res) { banco de dados.todos os documentos({incluir_docs: verdadeiro}).então(função(resultado) { res.enviar(resultado.linhas.mapa(função(item) { retorno item.doc; })); }, função(erro) { res.status(400).enviar(erro); }); }); aplicativo.obter("/people/:id", função(req, res) { se(!req.parâmetros.id) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `id`"}); } banco de dados.obter(req.parâmetros.id).então(função(resultado) { res.enviar(resultado); }, função(erro) { res.status(400).enviar(erro); }); }); aplicativo.postagem("/people", função(req, res) { se(!req.corpo.primeiro nome) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `firstname`"}); } mais se(!req.corpo.sobrenome) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `sobrenome`"}); } banco de dados.postagem(req.corpo).então(função(resultado) { res.enviar(resultado); }, função(erro) { res.status(400).enviar(erro); }); }); aplicativo.excluir("/people", função(req, res) { se(!req.corpo.id) { retorno res.status(400).enviar({"status": "error" (erro), "mensagem": "É necessário um `id`"}); } banco de dados.obter(req.corpo.id).então(função(resultado) { retorno banco de dados.remover(resultado); }).então(função(resultado) { res.enviar(resultado); }, função(erro) { res.status(400).enviar(erro); }); }); var servidor = aplicativo.ouvir(3000, função() { banco de dados.informações().então(função(informações) { console.registro(informações); console.registro("Escutando na porta %s...", servidor.endereço().porto); }); }); |
Para executar o aplicativo, você deve executar nó app.js
do Terminal ou do Prompt de Comando e, em seguida, acesse os pontos de extremidade http://localhost:3000 do cURL ou do aplicativo de sua preferência.
Conclusão
Você acabou de ver como incluir o PouchDB em um aplicativo da Web Node.js do lado do servidor em que o PouchDB se comunica com um banco de dados NoSQL Couchbase. Esse foi um dos muitos exemplos diferentes de como você pode incluir dispositivos móveis e servidores na mesma pilha porque o Sync Gateway está no meio. Em um post anterior Escrevi sobre o uso da API RESTful do Sync Gateway em vez do PouchDB. Esse exemplo também demonstrou o uso de dispositivos móveis e servidores com o Couchbase.