É desnecessário mencionar a crescente popularidade do Node.js para o desenvolvimento de aplicativos. O eBay tem executado um serviço de produção Node API desde 2011. O PayPal está reconstruindo ativamente seu front-end em Node. O site móvel do Walmart se tornou o maior aplicativo da Node, em termos de tráfego. No fim de semana de Ação de Graças em 2014, Os servidores Walmart processaram 1,5 bilhão de solicitações , 70 por cento dos quais foram entregues por meio de dispositivos móveis e com tecnologia Node.js. No lado do desenvolvimento, o gerenciador de pacotes Node ( acima do nível do mar ) continua a crescer rapidamente, ultrapassando recentemente 150.000 módulos hospedados.
Enquanto Ruby tem Rails e Pitão tem Django, a estrutura de desenvolvimento de aplicativo dominante para Node ainda não foi estabelecida. Mas, há um contendor poderoso ganhando força: LoopBack , uma estrutura de API de código aberto desenvolvida por San Mateo, Califórnia, empresa StrongLoop . StrongLoop é um importante contribuidor para os mais recentes Versão do nó , para não mencionar os mantenedores de longa data de Expressar , uma das estruturas Node mais populares que existem.
Vamos dar uma olhada mais de perto no LoopBack e em seus recursos, colocando tudo em prática e construindo um aplicativo de exemplo.
LoopBack é uma estrutura para criando APIs e conectá-los a fontes de dados de back-end. Construído sobre o Express, ele pode ter uma definição de modelo de dados e gerar facilmente uma API REST ponta a ponta totalmente funcional que pode ser chamada por qualquer cliente.
LoopBack vem com um cliente integrado, API Explorer . Usaremos isso porque torna mais fácil ver os resultados do nosso trabalho e para que nosso exemplo possa se concentrar na construção da própria API.
Obviamente, você precisará do Node instalado em sua máquina para acompanhar. Pegue Aqui . O npm vem com ele, para que você possa instalar os pacotes necessários facilmente. Vamos começar.
Nosso aplicativo irá gerenciar pessoas que gostariam de doar presentes, ou coisas de que não precisam mais, para alguém que possa precisar deles. Assim, os usuários serão Doadores e Receptores. Um doador pode criar um novo presente e ver a lista de presentes. Um receptor pode ver a lista de presentes de todos os usuários e pode reivindicar qualquer um que não tenha sido reivindicado. Claro, poderíamos construir Doadores e Receptores como funções separadas na mesma entidade (Usuário), mas vamos tentar separá-los para que possamos ver como construir relações no LoopBack. O nome deste aplicativo inovador será Dá a alguém .
Instale as ferramentas de linha de comando StrongLoop por meio do npm:
$ npm install -g strongloop
Em seguida, execute o gerador de aplicativos do LoopBack:
$ slc loopback _-----_ | | .--------------------------. |--(o)--| | Let's create a LoopBack | `---------´ | application! | ( _´U`_ ) '--------------------------' /___A___ | ~ | __'.___.'__ ´ ` |° ´ Y ` ? What's the name of your application? Givesomebody
Vamos adicionar um modelo. Nosso primeiro modelo se chamará Gift. LoopBack solicitará a fonte de dados e a classe base. Como ainda não configuramos a fonte de dados, podemos colocar db (memory)
. A classe base é uma classe de modelo gerada automaticamente e queremos usar PersistedModel
neste caso, uma vez que já contém todos os métodos CRUD usuais para nós. Em seguida, LoopBack pergunta se deve expor o modelo por meio de REST (sim) e o nome do serviço REST. Pressione Enter aqui para usar o padrão, que é simplesmente o plural do nome do modelo (no nosso caso, gifts
).
$ slc loopback:model ? Enter the model name: Gift ? Select the data-source to attach Gift to: (Use arrow keys) ❯ db (memory) ? Select model's base class: (Use arrow keys) Model ❯ PersistedModel ? Expose Gift via the REST API? (Y/n) Yes ? Custom plural form (used to build REST URL):
Por fim, fornecemos os nomes das propriedades, seus tipos de dados e sinalizadores obrigatório / não obrigatório. O presente terá name
e description
propriedades:
Let's add some Gift properties now. Enter an empty property name when done. ? Property name: name invoke loopback:property ? Property type: (Use arrow keys) ❯ string ? Required? (y/N)Yes
Insira um nome de propriedade vazio para indicar que você concluiu a definição das propriedades.
O gerador de modelo criará dois arquivos que definem o modelo no aplicativo common/models
: gift.json
e gift.js
. O arquivo JSON especifica todos os metadados sobre a entidade: propriedades, relações, validações, funções e nomes de métodos. O arquivo JavaScript é usado para definir o comportamento adicional e especificar ganchos remotos a serem chamados antes ou depois de certas operações (por exemplo, criar, atualizar ou excluir).
As outras duas entidades modelo serão nossos modelos de doador e receptor. Podemos criá-los usando o mesmo processo, mas desta vez vamos colocar User
como a classe base. Ele nos dará algumas propriedades como username
, password
, email
sai da caixa. Podemos adicionar apenas o nome e o país, por exemplo, para ter uma entidade completa. Para o Destinatário, queremos adicionar o endereço de entrega também.
Vamos dar uma olhada na estrutura do projeto gerada:
Os três diretórios principais são: - /server
- Contém scripts de aplicativo de nó e arquivos de configuração. - /client
- Contém .js, .html, .css e todos os outros arquivos estáticos. - /common
- Esta pasta é comum ao servidor e ao cliente. Os arquivos de modelo vão aqui.
Aqui está uma análise detalhada do conteúdo de cada diretório, retirado do Documentação do LoopBack :
Arquivo ou diretório | Descrição | Como acessar em código |
---|---|---|
Diretório de aplicativo de nível superior | ||
package.json | Especificação do pacote npm padrão. Vejo package.json | N / D |
/ diretório do servidor - arquivos de aplicativo do nó | ||
server.js | Arquivo principal do programa de aplicação. | N / D |
config.json | Configurações do aplicativo. Vejo config.json . | app.get('setting-name') |
datasources.json | Arquivo de configuração da fonte de dados. Vejo datasources.json .Para um exemplo, veja Crie uma nova fonte de dados . | app.datasources['datasource-name'] |
model-config.json | Arquivo de configuração do modelo. Vejo model-config.json .Para mais informações, veja Conectando modelos a fontes de dados . | N / D |
middleware.json | Arquivo de definição de middleware. Para mais informações, veja Definição de middleware . | N / D |
/boot diretório | Adicione scripts para executar a inicialização e configuração. Vejo scripts de inicialização . | Os scripts são executados automaticamente em ordem alfabética. |
/ diretório cliente - arquivos de aplicativo cliente | ||
README.md | Os geradores de LoopBack criam um arquivo README vazio no formato markdown. | N / D |
De outros | Adicione seus arquivos HTML, CSS e JavaScript do cliente. | |
/ diretório comum - arquivos de aplicativos compartilhados | ||
/models diretório | Arquivos de modelo personalizado:
| Nó: myModel = app.models.myModelName |
Em nosso exemplo, temos alguns relacionamentos importantes para modelar. Um doador pode doar muitos presentes, o que dá a relação Doador tem muitos presentes . Um receptor também pode receber muitos presentes, então também temos a relação O destinatário tem muitos presentes . Por outro lado, Presente pertence ao doador , e também pode pertencem ao receptor se o receptor decidir aceitá-lo. Vamos colocar isso na linguagem do LoopBack.
como se preparar para arquiteto de soluções com certificação aws
$ slc loopback:relation ? Select the model to create the relationship from: Donor ? Relation type: has many ? Choose a model to create a relationship with: Gift ? Enter the property name for the relation: gifts ? Optionally enter a custom foreign key: ? Require a through model? No
Observe que não há um modelo direto; estamos apenas mantendo a referência ao Dom.
Se repetirmos o procedimento acima para o receptor e adicionarmos dois pertence a relações com a Gift, vamos realizar o design do nosso modelo no lado posterior. O LoopBack atualiza automaticamente os arquivos JSON para os modelos para expressar exatamente o que acabamos de fazer por meio dessas caixas de diálogo simples:
// common/models/donor.json ... 'relations': { 'gifts': { 'type': 'hasMany', 'model': 'Gift', 'foreignKey': '' } }, ...
Agora vamos ver como anexar uma fonte de dados real para armazenar todos os dados do nosso aplicativo. Para os fins deste exemplo, usaremos MongoDB , mas o LoopBack tem módulos para se conectar com Oracle, MySQL, PostgreSQL, Redis e SQL Server.
Primeiro, instale o conector:
$ npm install --save loopback-connector-mongodb
Em seguida, adicione uma fonte de dados ao seu projeto:
$ slc loopback:datasource ? Enter the data-source name: givesomebody ? Select the connector for givesomebody: MongoDB (supported by StrongLoop)
A próxima etapa é configurar sua fonte de dados em server/datasources.json
. Use esta configuração para um servidor MongoDB local:
... 'givesomebody': { 'name': 'givesomebody', 'connector': 'mongodb', 'host': 'localhost', 'port': 27017, 'database': 'givesomebody', 'username': '', 'password': '' } ...
Finalmente, abra server/model-config.json
e altere o datasource
para todas as entidades que queremos persistir no banco de dados para 'givesomebody'
.
{ ... 'User': { 'dataSource': 'givesomebody' }, 'AccessToken': { 'dataSource': 'givesomebody', 'public': false }, 'ACL': { 'dataSource': 'givesomebody', 'public': false }, 'RoleMapping': { 'dataSource': 'givesomebody', 'public': false }, 'Role': { 'dataSource': 'givesomebody', 'public': false }, 'Gift': { 'dataSource': 'givesomebody', 'public': true }, 'Donor': { 'dataSource': 'givesomebody', 'public': true }, 'Receiver': { 'dataSource': 'givesomebody', 'public': true } }
É hora de ver o que construímos até agora! Usaremos a incrível ferramenta integrada, API Explorer , que pode ser usado como cliente para o serviço que acabamos de criar. Vamos tentar testar API REST chamadas.
Em uma janela separada, inicie o MongoDB com:
$ mongod
Execute o aplicativo com:
$ node .
Em seu navegador, vá para http://localhost:3000/explorer/
. Você pode ver suas entidades com a lista de operações disponíveis. Experimente adicionar um doador com um POST /Donors
ligar.
API Explorer é muito intuitivo; selecione qualquer um dos métodos expostos e o esquema do modelo correspondente será exibido no canto inferior direito. No data
área de texto, é possível escrever uma solicitação HTTP personalizada. Assim que a solicitação for preenchida, clique no botão “Experimente” e a resposta do servidor será exibida abaixo.
Como mencionado acima, uma das entidades que vem pré-construída com o LoopBack é a classe User. O usuário possui métodos de login e logout e pode ser vinculado a uma entidade AccessToken que mantém o token do usuário específico. Na verdade, um sistema completo de autenticação de usuário está pronto para ser retirado da caixa. Se tentarmos chamar /Donors/login
através API Explorer , aqui está a resposta que obtemos:
{ 'id': '9Kvp4zc0rTrH7IMMeRGwTNc6IqNxpVfv7D17DEcHHsgcAf9Z36A3CnPpZJ1iGrMS', 'ttl': 1209600, 'created': '2015-05-26T01:24:41.561Z', 'userId': '' }
O id
é na verdade o valor do AccessToken, gerado e persistido no banco de dados automaticamente. Como você vê aqui, é possível definir um token de acesso e usá-lo para cada solicitação subsequente.
Um método remoto é um método estático de um modelo, exposto em um ponto de extremidade REST customizado. Métodos remotos podem ser usados para realizar operações não fornecidas pela API REST do modelo padrão do LoopBack.
Além dos métodos CRUD que tiramos da caixa, podemos adicionar quantos métodos personalizados quisermos. Todos eles devem ir para o [model].js
Arquivo. No nosso caso, vamos adicionar um método remoto ao modelo de presente para verificar se o presente já está reservado e um para listar todos os presentes que não estão reservados.
Primeiro, vamos adicionar uma propriedade adicional ao modelo chamada reserved
. Basta adicionar isso às propriedades em gift.json
:
... 'reserved': { 'type': 'boolean' } ...
O método remoto em gift.js
deve ser parecido com isto:
module.exports = function(Gift) { // method which lists all free gifts Gift.listFree = function(cb) { Gift.find({ fields: { reserved: false } }, cb); }; // expose the above method through the REST Gift.remoteMethod('listFree', { returns: { arg: 'gifts', type: 'array' }, http: { path: '/list-free', verb: 'get' } }); // method to return if the gift is free Gift.isFree = function(id, cb) { var response; Gift.find({ fields: { id: id } }, function(err, gift) { if (err) return cb(err); if (gift.reserved) response = 'Sorry, the gift is reserved'; else response = 'Great, this gift can be yours'; }); cb(null, response); }; // expose the method through REST Gift.remoteMethod('isFree', { accepts: { arg: 'id', type: 'number' }, returns: { arg: 'response', type: 'string' }, http: { path: '/free', verb: 'post' } }); };
Portanto, para saber se um determinado presente está disponível, o cliente pode agora enviar uma solicitação POST para /api/Gifts/free
, passando o id
do presente em questão.
Às vezes, é necessário executar algum método antes ou depois do método remoto. Você pode definir dois tipos de ganchos remotos:
beforeRemote()
é executado antes do método remoto.afterRemote()
é executado após o método remoto.Em ambos os casos, você fornece dois argumentos: uma string que corresponde ao método remoto ao qual você deseja “ligar” a sua função e a função de retorno de chamada. Muito do poder dos ganchos remotos é que a string pode incluir curingas, portanto, é acionada por qualquer método de correspondência.
Em nosso caso, vamos definir um gancho para imprimir informações no console sempre que um novo doador for criado. Para fazer isso, vamos adicionar um gancho “antes de criar” em donor.js
:
module.exports = function(Donor) { Donor.beforeRemote('create', function(context, donor, next) { console.log('Saving new donor with name: ', context.req.body.name); next(); }); };
A solicitação é chamada com o dado context
e o next()
o retorno de chamada no middleware (discutido abaixo) é chamado após a execução do gancho.
Os aplicativos LoopBack acessam dados por meio de modelos, portanto, controlar o acesso aos dados significa definir restrições aos modelos; isto é, especificando quem ou o que pode ler e gravar os dados ou executar métodos nos modelos. Os controles de acesso do LoopBack são determinados por listas de controle de acesso ou ACLs.
Vamos permitir que doadores e destinatários não registrados vejam os presentes, mas apenas os doadores registrados criem e excluam os presentes.
$ slc loopback:acl
Para começar, vamos negar a todos o acesso a todos os endpoints.
? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: All (match all types) ? Select the role: All users ? Select the permission to apply: Explicitly deny access
Em seguida, permita que todos leiam os modelos de presente:
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: Read ? Select the role: All users ? Select the permission to apply: Explicitly grant access
Então, queremos permitir que usuários autenticados criem presentes:
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: A single method ? Enter the method name: create ? Select the role: Any authenticated user ? Select the permission to apply: Explicitly grant access
E, finalmente, vamos permitir que o proprietário do presente faça quaisquer alterações:
$ slc loopback:acl ? Select the model to apply the ACL entry to: Gift ? Select the ACL scope: All methods and properties ? Select the access type: Write ? Select the role: The user owning the object ? Select the permission to apply: Explicitly grant access
Agora, quando revisarmos gift.json
, tudo deve estar no lugar:
'acls': [ { 'accessType': '*', 'principalType': 'ROLE', 'principalId': '$everyone', 'permission': 'DENY' }, { 'accessType': 'READ', 'principalType': 'ROLE', 'principalId': '$everyone', 'permission': 'ALLOW' }, { 'accessType': 'EXECUTE', 'principalType': 'ROLE', 'principalId': '$authenticated', 'permission': 'ALLOW', 'property': 'create' } ],
Uma observação importante aqui: $authenticated
é uma função predefinida que corresponde a todos os usuários do sistema (doadores e receptores), mas queremos apenas permitir que os doadores criem novos presentes. Portanto, precisamos de uma função personalizada. Como Role é mais uma entidade que tiramos da caixa, podemos aproveitar sua chamada de API para criar o $authenticatedDonor
função na função de inicialização e, em seguida, basta modificar pricipalId
em gift.json
.
Será necessário criar um novo arquivo, server/boot/script.js
, e adicionar o seguinte código:
Role.create({ name: 'authenticatedDonor' }, function(err, role) { if (err) return debug(err); })
A entidade RoleMapping mapeia funções para usuários. Certifique-se de que Role e RoleMapping sejam expostos por meio de REST. Em server/model-config.json
, verifique se 'public'
está definido como true
para a entidade de função. Então, em donor.js
, podemos escrever um gancho “antes de criar” que mapeará o userID
e roleID
na chamada RoleMapping POST API.
Middleware contém funções que são executadas quando uma solicitação é feita ao terminal REST. Como o LoopBack é baseado no Express, ele usa middleware Express com um conceito adicional, chamado de “fases de middleware”. As fases são usadas para definir claramente a ordem em que as funções no middleware são chamadas.
Aqui está a lista de fases predefinidas, conforme fornecido nos documentos do LoopBack:
Cada fase possui três subfases. Por exemplo, as subfases da fase inicial são:
Vamos dar uma olhada rápida em nosso middleware.json padrão:
{ 'initial:before': { 'loopback#favicon': {} }, 'initial': { 'compression': {}, 'cors': { 'params': { 'origin': true, 'credentials': true, 'maxAge': 86400 } } }, 'session': { }, 'auth': { }, 'parse': { }, 'routes': { }, 'files': { }, 'final': { 'loopback#urlNotFound': {} }, 'final:after': { 'errorhandler': {} } }
Na fase inicial, chamamos loopback.favicon()
(loopback#favicon
é o id de middleware para essa chamada). Em seguida, módulos npm de terceiros compression
e cors
são chamados (com ou sem parâmetros). Na fase final, temos mais duas ligações. urlNotFound
é uma chamada LoopBack e errorhandler
é um módulo de terceiros. Este exemplo deve demonstrar que muitas chamadas internas podem ser usadas da mesma forma que os módulos npm externos. E, claro, sempre podemos criar nosso próprio middleware e chamá-los por meio deste arquivo JSON.
loopback-boot
Para finalizar, vamos mencionar um módulo que exporta o boot()
função que inicializa o aplicativo. Em server/server.js
você encontrará o seguinte trecho de código, que inicializa o aplicativo:
boot(app, __dirname, function(err) { if (err) throw err; // start the server if `$ node server.js` if (require.main === module) app.start(); });
Este script pesquisará o server/boot
pasta e carregue todos os scripts que encontrar lá em ordem alfabética. Assim, em server/boot
, podemos especificar qualquer script que deve ser executado no início. Um exemplo é explorer.js
, que executa API Explorer , o cliente que usamos para testar nossa API.
Antes de deixá-lo, gostaria de mencionar StrongLoop Arc , uma IU gráfica que pode ser usada como alternativa a slc
ferramentas de linha de comando. Também inclui ferramentas para construção, criação de perfil e monitoramento de aplicativos Node. Para aqueles que não são fãs de linha de comando, definitivamente vale a pena tentar. No entanto, o StrongLoop Arc está prestes a ser descontinuado e sua funcionalidade está sendo integrada ao IBM API Connect Developer Toolkit .
De um modo geral, o LoopBack pode economizar muito trabalho manual, já que você está obtendo um monte de coisas fora da caixa. Ele permite que você se concentre em problemas específicos de aplicativos e na lógica de negócios. Se seu aplicativo for baseado em operações CRUD e manipular entidades predefinidas, se você estiver cansado de reescrever a infraestrutura de autenticação e autorização do usuário quando toneladas de desenvolvedores escreveram isso antes de você, ou se você quiser aproveitar todas as vantagens de uma grande estrutura da web como Express, então construir sua API REST com O LoopBack pode realizar seus sonhos. É moleza!