Koa.js - Guia rápido

Uma estrutura de aplicativo da web fornece uma API simples para construir sites, aplicativos da web e back-ends. Você não precisa se preocupar com protocolos de baixo nível, processos, etc.

O que é Koa?

Koa fornece uma interface mínima para construir aplicativos. É uma estrutura muito pequena (600 LoC) que fornece as ferramentas necessárias para construir aplicativos e é bastante flexível. Existem vários módulos disponíveis no npm para Koa, que podem ser conectados diretamente a ele. Koa pode ser considerado o núcleo do express.js sem todos os sinos e assobios.

Por que Koa?

Koa tem uma pegada pequena (600 LoC) e é uma camada muito fina de abstração sobre o nó para criar aplicativos do lado do servidor. É totalmente plugável e possui uma enorme comunidade. Isso também nos permite estender facilmente o Koa e usá-lo de acordo com nossas necessidades. Ele é construído usando a tecnologia de ponta (ES6), o que lhe dá uma vantagem sobre estruturas mais antigas, como express.

Pug

Pug (anteriormente conhecido como Jade) é uma linguagem concisa para escrever modelos HTML.

  • Produz HTML
  • Suporta código dinâmico
  • Suporta capacidade de reutilização (DRY)

É uma das linguagens de modelagem mais populares usadas com Koa.

MongoDB e Mongoose

MongoDB é um banco de dados de documentos de código aberto projetado para facilidade de desenvolvimento e escalonamento. Usaremos esse banco de dados para armazenar dados.

Mongoose é uma API cliente para node.js que torna mais fácil acessar nosso banco de dados de nosso aplicativo Koa.

Para começar a desenvolver usando a estrutura Koa, você precisa ter o Node e o npm (gerenciador de pacotes do nó) instalados. Se você ainda não os tem, vá para a configuração do nó para instalar o nó em seu sistema local. Confirme se o nó e o npm estão instalados executando os seguintes comandos em seu terminal.

$ node --version
$ npm --version

Você deve receber uma saída semelhante a -

v5.0.0
3.5.2

Certifique-se de que a versão do seu nó seja superior a 6.5.0. Agora que temos o Node e o npm configurados, vamos entender o que é o npm e como usá-lo.

Node Package Manager (npm)

npm é o gerenciador de pacotes para o nó. O npm Registry é uma coleção pública de pacotes de código-fonte aberto para Node.js, aplicativos da web front-end, aplicativos móveis, robôs, roteadores e inúmeras outras necessidades da comunidade JavaScript. O npm nos permite acessar todos esses pacotes e instalá-los localmente. Você pode navegar pela lista de pacotes disponíveis no npm em npmJS .

Como usar o npm?

Existem duas maneiras de instalar um pacote usando o npm - global e localmente.

Globally- Este método é geralmente usado para instalar ferramentas de desenvolvimento e pacotes baseados em CLI. Para instalar um pacote globalmente, use o seguinte comando.

$ npm install -g <package-name>

Locally- Este método é geralmente usado para instalar estruturas e bibliotecas. Um pacote instalado localmente pode ser usado apenas no diretório em que está instalado. Para instalar um pacote localmente, use o mesmo comando acima sem o -g bandeira.

$ npm install <package-name>

Sempre que criamos um projeto usando npm, precisamos fornecer um arquivo package.json, que contém todos os detalhes sobre nosso projeto. O npm facilita a configuração desse arquivo. Vamos montar nosso projeto de desenvolvimento.

Step 1 - Abra seu terminal / cmd, crie uma nova pasta chamada hello-world e faça um cd nela -

Step 2 - Agora, para criar o arquivo package.json usando npm, use o seguinte.

npm init

Ele solicitará as seguintes informações -

Continue pressionando enter e digite seu nome no campo “nome do autor”.

Step 3- Agora que temos nosso arquivo package.json configurado, instalaremos o Koa. Para instalar o Koa e adicioná-lo ao nosso arquivo package.json, use o seguinte comando.

$ npm install --save koa

Para confirmar se o Koa está instalado corretamente, execute o seguinte comando.

$ ls node_modules #(dir node_modules for windows)

Tip - o --save bandeira pode ser substituída por -Sbandeira. Este sinalizador garante que Koa seja adicionado como uma dependência ao nosso arquivo package.json. Isso tem uma vantagem, da próxima vez que precisarmos instalar todas as dependências de nosso projeto, basta executar o comando npm install e ele encontrará as dependências neste arquivo e as instalará para nós.

Isso é tudo de que precisamos para iniciar o desenvolvimento usando a estrutura Koa. Para tornar nosso processo de desenvolvimento muito mais fácil, instalaremos uma ferramenta do npm, o nodemon. O que essa ferramenta faz é reiniciar nosso servidor assim que fazemos uma alteração em qualquer um de nossos arquivos, caso contrário, precisamos reiniciar o servidor manualmente após cada modificação de arquivo. Para instalar o nodemon, use o seguinte comando.

$ npm install -g nodemon

Agora estamos todos prontos para mergulhar em Koa!

Depois de configurar o desenvolvimento, é hora de começar a desenvolver nosso primeiro aplicativo usando Koa. Crie um novo arquivo chamadoapp.js e digite o seguinte nele.

var koa = require('koa');
var app = new koa();

app.use(function* (){
   this.body = 'Hello world!';
});

app.listen(3000, function(){
   console.log('Server running on https://localhost:3000')
});

Salve o arquivo, vá ao seu terminal e digite.

$ nodemon app.js

Isso iniciará o servidor. Para testar este aplicativo, abra seu navegador e vá parahttps://localhost:3000 e você deve receber a seguinte mensagem.

Como funciona este aplicativo?

A primeira linha importa Koa em nosso arquivo. Temos acesso à sua API através da variável Koa. Nós o usamos para criar um aplicativo e atribuí-lo ao var app.

app.use(function)- Esta função é um middleware, que é chamado sempre que nosso servidor recebe uma solicitação. Aprenderemos mais sobre middleware nos capítulos subsequentes. A função de retorno de chamada é um gerador, que veremos no próximo capítulo. O contexto desse gerador é chamado de contexto em Koa. Este contexto é usado para acessar e modificar os objetos de solicitação e resposta. Estamos definindo o corpo desta resposta para serHello world!.

app.listen(port, function)- Esta função liga e escuta as conexões na porta especificada. A porta é o único parâmetro obrigatório aqui. A função de retorno de chamada é executada, se o aplicativo for executado com sucesso.

Um dos novos recursos mais interessantes do JavaScript ES6 é uma nova espécie de função, chamada de gerador. Antes dos geradores, todo o script era usado para executar normalmente de cima para baixo, sem uma maneira fácil de parar a execução do código e retomar com a mesma pilha posteriormente. Geradores são funções que podem ser encerradas e posteriormente reinseridas. Seu contexto (ligações de variáveis) serão salvos nas reentradas.

Os geradores nos permitem interromper a execução do código no meio. Portanto, vamos dar uma olhada em um gerador simples.

var generator_func = function* (){
   yield 1;
   yield 2;
};

var itr = generator_func();
console.log(itr.next());
console.log(itr.next());
console.log(itr.next());

Ao executar o código acima, o seguinte será o resultado.

{ value: 1, done: false }
{ value: 2, done: false }
{ value: undefined, done: true }

Vamos dar uma olhada dentro do código acima. Primeiro criamos um gerador chamadogenerator_func(). Criamos uma instância desta função de aparência estranha e atribuímos aitr. Então começamos a ligarnext() nesta variável itr.

Chamar next () inicia o gerador e ele funciona até atingir um rendimento. Em seguida, ele retorna o objeto com valor e feito, onde o valor possui a expressão valor. Esta expressão pode ser qualquer coisa. Neste ponto, ele pausa a execução. Novamente, quando chamamos esta função (próxima), o gerador retoma a execução do último ponto de rendimento com o estado da função sendo o mesmo no momento da pausa, até o próximo ponto de rendimento. Isso é feito até que não haja mais pontos de rendimento no código.

Geradores em Koa

Então, por que estamos discutindo geradores neste tutorial. Como você deve se lembrar do programa hello world, usamos umfunction* ()notação para passar um retorno de chamada para app.use (). Koa é um objeto que contém uma matriz de funções geradoras de middleware, todas compostas e executadas como uma pilha a cada solicitação. Koa também implementa o downstreaming seguido pelo upstreaming do fluxo de controle.

Dê uma olhada no exemplo a seguir para entender isso de uma maneira melhor.

var koa = require('koa');
var app = koa();
 
app.use(function* (next) {
   //do something before yielding to next generator function 
   
   //in line which will be 1st event in downstream
   console.log("1");
   yield next;
 
   //do something when the execution returns upstream, 
   //this will be last event in upstream
   console.log("2");
});
app.use(function* (next) {
   // This shall be 2nd event downstream
   console.log("3");
   yield next;
 
   // This would be 2nd event upstream
   console.log("4");
});
app.use(function* () { 
   // Here it would be last function downstream
   console.log("5");
   
   // Set response body
   this.body = "Hello Generators";

   // First event of upstream (from the last to first)
   console.log("6");
});

app.listen(3000);

Ao executar o código acima e navegar para https://localhost:3000/ obtemos a seguinte saída em nosso console.

1
3
5
6
4
2

É essencialmente assim que Koa usa geradores. Ele nos permite criar um middleware compacto usando essa propriedade e escrever código para as funcionalidades upstream e downstream, poupando-nos assim de callbacks.

Os frameworks da Web fornecem recursos como páginas HTML, scripts, imagens, etc. em diferentes rotas. Koa não oferece suporte a rotas no módulo principal. Precisamos usar o módulo do roteador Koa para criar rotas facilmente no Koa. Instale este módulo usando o seguinte comando.

npm install --save koa-router

Agora que temos o roteador Koa instalado, vamos ver um exemplo simples de rota GET.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();              //Instantiate the router
_.get('/hello', getMessage);   // Define routes

function *getMessage() {
   this.body = "Hello world!";
};

app.use(_.routes());           //Use the routes defined using the router
app.listen(3000);

Se executarmos nosso aplicativo e formos para localhost: 3000 / hello, o servidor receberá uma solicitação get na rota "/ hello". Nosso aplicativo Koa executa a função de retorno de chamada anexada a esta rota e envia "Hello World!" como a resposta.

Também podemos ter vários métodos diferentes na mesma rota. Por exemplo,

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router(); //Instantiate the router

_.get('/hello', getMessage);
_.post('/hello', postMessage);

function *getMessage() {
	this.body = "Hello world!";
};
function *postMessage() {
   this.body = "You just called the post method at '/hello'!\n";
};
app.use(_.routes()); //Use the routes defined using the router
app.listen(3000);

Para testar esta solicitação, abra seu terminal e use cURL para executar a seguinte solicitação

curl -X POST "https://localhost:3000/hello"

Um método especial, all, é fornecido por express para lidar com todos os tipos de métodos http em uma rota particular usando a mesma função. Para usar este método, tente o seguinte -

_.all('/test', allMessage);

function *allMessage(){
   this.body = "All HTTP calls regardless of the verb will get this response";
};

Agora podemos definir rotas; eles são estáticos ou fixos. Para usar rotas dinâmicas, precisamos fornecer diferentes tipos de rotas. O uso de rotas dinâmicas nos permite passar parâmetros e processar com base neles. A seguir está um exemplo de uma rota dinâmica.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();

_.get('/:id', sendID);

function *sendID() {
   this.body = 'The id you specified is ' + this.params.id;
}

app.use(_.routes());
app.listen(3000);

Para testar isso vá para https://localhost:3000/123. Você obterá a seguinte resposta.

Você pode substituir '123' no URL por qualquer outra coisa e isso será refletido na resposta. A seguir está um exemplo complexo do acima.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();

_.get('/things/:name/:id', sendIdAndName);

function *sendIdAndName(){
   this.body = 'id: ' + this.params.id + ' and name: ' + this.params.name;
};

app.use(_.routes());

app.listen(3000);

Para testar isso vá para https://localhost:3000/things/tutorialspoint/12345.

Você pode usar o this.paramsobjeto para acessar todos os parâmetros que você passa na URL. Observe que os dois acima têm caminhos diferentes. Eles nunca se sobreporão. Além disso, se você quiser executar o código ao obter '/ things', precisará defini-lo separadamente.

Rotas com correspondência de padrão

Você também pode usar regex para restringir a correspondência de parâmetro de URL. Digamos que você precise que o id tenha um número de cinco dígitos. Você pode usar a seguinte definição de rota.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();

_.get('/things/:id([0-9]{5})', sendID);

function *sendID(){
   this.body = 'id: ' + this.params.id;
}

app.use(_.routes());
app.listen(3000);

Observe que isso vai onlycorresponder às solicitações que têm um id de 5 dígitos. Você pode usar regexes mais complexas para corresponder / validar suas rotas. Se nenhuma de suas rotas corresponder à solicitação, você receberá uma mensagem Não encontrado como resposta.

Por exemplo, se definirmos as mesmas rotas acima, ao solicitar um URL válido, obtemos -

O método HTTP é fornecido na solicitação e especifica a operação que o cliente solicitou. A tabela a seguir resume os métodos HTTP comumente usados.

Sr. Não. Método e Descrição
1

GET

O método GET solicita uma representação do recurso especificado. As solicitações usando GET devem apenas recuperar dados e não devem ter nenhum outro efeito.

2

POST

O método POST solicita que o servidor aceite os dados incluídos na solicitação como um novo objeto / entidade do recurso identificado pelo URI.

3

PUT

O método PUT solicita que o servidor aceite os dados incluídos na solicitação como uma modificação do objeto existente identificado pelo URI. Se não existir, o método PUT deve criar um.

4

DELETE

O método DELETE solicita que o servidor exclua o recurso especificado.

Esses são os métodos HTTP mais comuns. Para saber mais sobre eles, vá parahttps://www.tutorialspoint.com/http/http_methods.htm.

Um objeto Koa Request é uma abstração no topo do objeto de solicitação vanilla do nó, fornecendo funcionalidade adicional que é útil para o desenvolvimento de servidor HTTP diário. O objeto de solicitação Koa é incorporado ao objeto de contexto,this. Vamos fazer logout do objeto de solicitação sempre que recebermos uma solicitação.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();

_.get('/hello', getMessage);

function *getMessage(){
   console.log(this.request);
   this.body = 'Your request has been logged.';
}
app.use(_.routes());
app.listen(3000);

Quando você executa este código e navega para https://localhost:3000/hello, você receberá a seguinte resposta.

No console, você obterá o objeto de solicitação desconectado.

{ 
   method: 'GET',
   url: '/hello/',
   header: 
   { 
      host: 'localhost:3000',
      connection: 'keep-alive',
      'upgrade-insecure-requests': '1',
      'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) 
         AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36',
      accept: 'text/html,application/xhtml+xml,
         application/xml;q = 0.9,image/webp,*/*;q = 0.8',
      dnt: '1',
      'accept-encoding': 'gzip, deflate, sdch',
      'accept-language': 'en-US,en;q = 0.8' 
   }
}

Temos acesso a muitas propriedades úteis da solicitação usando este objeto. Vejamos alguns exemplos.

request.header

Fornece todos os cabeçalhos de solicitação.

request.method

Fornece o método de solicitação (GET, POST, etc.)

request.href

Fornece o URL de solicitação completo.

request.path

Fornece o caminho da solicitação. Sem string de consulta e url de base.

request.query

Fornece a string de consulta analisada. Por exemplo, se registrarmos isso em uma solicitação comohttps://localhost:3000/hello/?name=Ayush&age=20&country=India, então obteremos o seguinte objeto.

{
   name: 'Ayush',
   age: '20',
   country: 'India'
}

request.accepts (type)

Esta função retorna verdadeiro ou falso com base no fato de os recursos solicitados aceitarem o tipo de solicitação fornecido.

Você pode ler mais sobre o objeto de solicitação nos documentos em Solicitação .

Um objeto Koa Response é uma abstração no topo do objeto de resposta vanilla do nó, fornecendo funcionalidade adicional que é útil para o desenvolvimento de servidor HTTP diário. O objeto de resposta Koa está embutido no objeto de contexto,this. Vamos fazer logout do objeto de resposta sempre que recebermos uma solicitação.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();

_.get('/hello', getMessage);

function *getMessage(){
   this.body = 'Your request has been logged.';
   console.log(this.response);
}

app.use(_.routes());
app.listen(3000);

Quando você executa este código e navega para https://localhost:3000/hello então você receberá a seguinte resposta.

No console, você obterá o objeto de solicitação desconectado.

{ 
   status: 200,
   message: 'OK',
   header: 
   {
      'content-type': 'text/plain; charset=utf-8',
      'content-length': '12' 
   },
   body: 'Your request has been logged.' 
}

O status e a mensagem são definidos automaticamente por Koa, mas podem ser modificados por nós. Se não definirmos o corpo da resposta, o código de status será definido como 404. Assim que definirmos o corpo da resposta, o status será definido como 200 por padrão. Podemos substituir explicitamente esse comportamento.

Temos acesso a muitas propriedades úteis da resposta usando este objeto. Vejamos alguns exemplos -

response.header

Fornece todos os cabeçalhos de resposta.

response.status

Fornece o status da resposta (200, 404, 500, etc.). Esta propriedade também é usada para definir o status da resposta.

response.message

Fornece a mensagem de resposta. Esta propriedade também é usada para definir mensagens personalizadas com respostas. Ele está associado a response.status.

response.body

Obtenha ou defina o corpo da resposta. Normalmente, acessamos usando o objeto de contexto. Esta é apenas outra forma de acessá-lo. O corpo pode ser do tipo: String, Buffer, Stream, Object ou Null.

response.type

Obtenha ou defina o tipo de conteúdo da resposta atual.

response.get (campo)

Esta função é usada para obter os valores dos cabeçalhos com campo de valor que não diferencia maiúsculas de minúsculas.

response.set (campo, valor)

Esta função é usada para definir um cabeçalho na resposta usando o par de campo e valor.

response.remove (campo)

Esta função é usada para remover um cabeçalho da resposta usando um nome de campo.

Você pode ler mais sobre o objeto de resposta nos documentos em Response .

O redirecionamento é muito importante ao criar sites. Se um URL malformado for solicitado ou se houver alguns erros em seu servidor, você deve redirecioná-los para as respectivas páginas de erro. Os redirecionamentos também podem ser usados ​​para manter as pessoas fora das áreas restritas do seu site.

Vamos criar uma página de erro e redirecionar para essa página sempre que alguém solicitar um URL malformado.

var koa = require('koa');
var router = require('koa-router');
var app = koa();
var _ = router();

_.get('/not_found', printErrorMessage);
_.get('/hello', printHelloMessage);

app.use(_.routes());
app.use(handle404Errors);

function *printErrorMessage() {
   this.status = 404;
   this.body = "Sorry we do not have this resource.";
}
function *printHelloMessage() {
   this.status = 200;
   this.body = "Hey there!";
}
function *handle404Errors(next) {
   if (404 != this.status) return;
   this.redirect('/not_found');
}
app.listen(3000);

Quando executamos este código e navegamos para qualquer rota diferente de / hello, seremos redirecionados para / not_found. Colocamos o middleware no final (chamada de função app.use para este middleware). Isso garante que chegaremos finalmente ao middleware e enviaremos a resposta correspondente. A seguir estão os resultados que vemos quando executamos o código acima.

Quando navegamos para https://localhost:3000/hello, nós temos -

Se navegarmos para qualquer outra rota, obtemos -

O tratamento de erros desempenha um papel importante na construção de aplicativos da web. Koa também usa middleware para essa finalidade.

No Koa, você adiciona um middleware que faz try { yield next }como um dos primeiros middleware. Se encontrarmos algum erro downstream, retornamos à cláusula catch associada e tratamos o erro aqui. Por exemplo -

var koa = require('koa');
var app = koa();

//Error handling middleware
app.use(function *(next) {
   try {
      yield next;
   } catch (err) {
      this.status = err.status || 500;
      this.body = err.message;
      this.app.emit('error', err, this);
   }
});

//Create an error in the next middleware
//Set the error message and status code and throw it using context object

app.use(function *(next) {
   //This will set status and message
   this.throw('Error Message', 500);
});

app.listen(3000);

Criamos deliberadamente um erro no código acima e estamos tratando do erro no primeiro bloco catch de middleware. Isso é então emitido para o nosso console e enviado como resposta ao nosso cliente. A seguir está a mensagem de erro que recebemos quando acionamos esse erro.

InternalServerError: Error Message
   at Object.module.exports.throw 
      (/home/ayushgp/learning/koa.js/node_modules/koa/lib/context.js:91:23)
   at Object.<anonymous> (/home/ayushgp/learning/koa.js/error.js:18:13)
   at next (native)
   at onFulfilled (/home/ayushgp/learning/koa.js/node_modules/co/index.js:65:19)
   at /home/ayushgp/learning/koa.js/node_modules/co/index.js:54:5
   at Object.co (/home/ayushgp/learning/koa.js/node_modules/co/index.js:50:10)
   at Object.toPromise (/home/ayushgp/learning/koa.js/node_modules/co/index.js:118:63)
   at next (/home/ayushgp/learning/koa.js/node_modules/co/index.js:99:29)
   at onFulfilled (/home/ayushgp/learning/koa.js/node_modules/co/index.js:69:7)
   at /home/ayushgp/learning/koa.js/node_modules/co/index.js:54:5

Neste momento, qualquer solicitação enviada ao servidor resultará neste erro.

Funções de middleware são funções que têm acesso ao context objecte a próxima função de middleware no ciclo de solicitação-resposta do aplicativo. Essas funções são usadas para modificar os objetos de solicitação e resposta para tarefas como análise de corpos de solicitação, adição de cabeçalhos de resposta etc. Koa dá um passo adiante, produzindo'downstream', então fluindo o controle de volta 'upstream'. Este efeito é chamadocascading.

A seguir está um exemplo simples de uma função de middleware em ação.

var koa = require('koa');
var app = koa();
var _ = router();

//Simple request time logger
app.use(function* (next) {
   console.log("A new request received at " + Date.now());
   
   //This function call is very important. It tells that more processing is 
   //required for the current request and is in the next middleware function/route handler.
   yield next;
});

app.listen(3000);

O middleware acima é chamado para cada solicitação no servidor. Assim, após cada solicitação, obteremos a seguinte mensagem no console.

A new request received at 1467267512545

Para restringir a uma rota específica (e todas as suas sub-rotas), precisamos apenas criar as rotas como fizemos para o roteamento. Na verdade, são esses middleware apenas que atendem ao nosso pedido.

Por exemplo,

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var _ = router();

//Simple request time logger
_.get('/request/*', function* (next) {
   console.log("A new request received at " + Date.now());
   yield next;
});

app.use(_.routes());
app.listen(3000);

Agora, sempre que você solicitar qualquer sub-rota de '/ request', só então ele registrará a hora.

Ordem das chamadas de middleware

Uma das coisas mais importantes sobre o middleware em Koa é que a ordem em que são escritos / incluídos em seu arquivo é a ordem em que são executados no downstream. Assim que atingimos uma declaração de rendimento em um middleware, ele alterna para o próximo middleware da linha, até chegarmos ao último. Então, novamente começamos a mover para cima e retomar as funções de declarações de rendimento.

Por exemplo, no fragmento de código a seguir, a primeira função executa primeiro até o rendimento, a seguir o segundo middleware até o rendimento e depois o terceiro. Como não temos mais middleware aqui, começamos a voltar para cima, executando na ordem inversa, ou seja, terceiro, segundo, primeiro. Este exemplo resume como usar o middleware da maneira Koa.

var koa = require('koa');
var app = koa();

//Order of middlewares
app.use(first);
app.use(second);
app.use(third);

function *first(next) {
   console.log("I'll be logged first. ");
   
   //Now we yield to the next middleware
   yield next;
   
   //We'll come back here at the end after all other middlewares have ended
   console.log("I'll be logged last. ");
};

function *second(next) {
   console.log("I'll be logged second. ");
   yield next;
   console.log("I'll be logged fifth. ");
};

function *third(next) {
   console.log("I'll be logged third. ");
   yield next;
   console.log("I'll be logged fourth. ");
};

app.listen(3000);

Quando visitarmos '/' após executar este código, em nosso console obteremos -

I'll be logged first. 
I'll be logged second. 
I'll be logged third. 
I'll be logged fourth. 
I'll be logged fifth. 
I'll be logged last.

O diagrama a seguir resume o que realmente está acontecendo no exemplo acima.

Agora que sabemos como criar nosso próprio middleware, vamos discutir alguns dos middlewares criados pela comunidade mais comumente usados.

Middleware de Terceiros

Uma lista de middleware de terceiros para expresso está disponível aqui. A seguir estão alguns dos middlewares mais comumente usados ​​-

  • koa-bodyparser
  • koa-router
  • koa-static
  • koa-compress

Discutiremos vários middleware nos capítulos subsequentes.

Pug é um motor de modelagem. Os mecanismos de modelagem são usados ​​para remover a confusão de nosso código de servidor com HTML, concatenando strings aos modelos HTML existentes. Pug é um motor de modelagem muito poderoso, que possui uma variedade de recursos, comofilters, includes, inheritance, interpolation, etc. Há muito terreno a percorrer sobre isso.

Para usar o Pug com Koa, precisamos instalá-lo usando o seguinte comando.

$ npm install --save pug koa-pug

Depois que o pug estiver instalado, defina-o como o mecanismo de modelagem do seu aplicativo. Adicione o seguinte código ao seu arquivo app.js.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var Pug = require('koa-pug');
var pug = new Pug({
   viewPath: './views',
   basedir: './views',
   app: app //Equivalent to app.use(pug)
});

var _ = router(); //Instantiate the router

app.use(_.routes()); //Use the routes defined using the router
app.listen(3000);

Agora, crie um novo diretório chamado views. Dentro do diretório, crie um arquivo denominado first_view.pug e insira os seguintes dados nele.

doctype html
html
   head
      title = "Hello Pug"
   body
      p.greetings#people Hello Views!

Para executar esta página, adicione a seguinte rota ao seu aplicativo.

_.get('/hello', getMessage); // Define routes

function *getMessage(){
   this.render('first_view');
};

Você receberá a saída como -

O que o Pug faz é converter essa marcação de aparência muito simples em html. Não precisamos acompanhar o fechamento de nossas tags, nem usar palavras-chave class e id, em vez disso, usar '.' e '#' para defini-los. O código acima é primeiro convertido para

<!DOCTYPE html>
<html>
   <head>
      <title>Hello Pug</title>
   </head>
    
   <body>
      <p class = "greetings" id = "people">Hello Views!</p>
   </body>
</html>

Pug é capaz de fazer muito mais do que simplificar a marcação HTML. Vamos explorar alguns desses recursos do Pug.

Tags simples

As marcas são aninhadas de acordo com sua indentação. Como no exemplo acima,<title> foi recuado dentro do <head>tag, então estava dentro dela. No entanto, o<body> etiqueta estava no mesmo recuo, portanto, era irmã de <head> tag.

Não precisamos fechar as tags. Assim que Pug encontra a próxima tag no mesmo nível ou no nível de recuo externo, ele fecha a tag para nós.

Existem três métodos para colocar texto dentro de uma tag -

  • Espaço separado -
h1 Welcome to Pug
  • Texto encadeado -
div
   | To insert multiline text, 
   | You can use the pipe operator.
  • Bloco de texto -
div.
   But that gets tedious if you have a lot of text. 
   You can use "." at the end of tag to denote block of text. 
   To put tags inside this block, simply enter tag in a new line and 
   indent it accordingly.

Comentários

Pug usa a mesma sintaxe do JavaScript (//) para criar comentários. Esses comentários são convertidos em comentários html (<! - comentário ->). Por exemplo,

//This is a Pug comment

Este comentário é convertido em -

<!--This is a Pug comment-->

Atributos

Para definir atributos, usamos uma lista de atributos separados por vírgulas, entre parênteses. Os atributos de classe e ID têm representações especiais. A linha de código a seguir cobre a definição de atributos, classes e id para uma determinada tag html.

div.container.column.main#division(width = "100",height = "100")

Esta linha de código é convertida em -

<div class = "container column main" id = "division" width = "100" height = "100"></div>

Passando Valores para Modelos

Quando renderizamos um template Pug, podemos passar para ele um valor de nosso gerenciador de rota, que podemos então usar em nosso template. Crie um novo manipulador de rota com o código a seguir.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var Pug = require('koa-pug');
var pug = new Pug({
   viewPath: './views',
   basedir: './views',
   app: app // equals to pug.use(app) and app.use(pug.middleware)
});

var _ = router(); //Instantiate the router

_.get('//dynamic_view', dynamicMessage); // Define routes

function *dynamicMessage(){
   this.render('dynamic', {
      name: "TutorialsPoint", 
      url:"https://www.tutorialspoint.com"
   });
};

app.use(_.routes()); //Use the routes defined using the router
app.listen(3000);

Em seguida, crie um novo arquivo de visualização no diretório de visualizações, denominado dynamic.pug, usando o código a seguir.

html
   head
      title = name
   body
      h1 = name
      a(href = url) URL

Abrir localhost:3000/dynamicem seu navegador e o seguinte deve ser a saída. -

Também podemos usar essas variáveis ​​passadas no texto. Para inserir variáveis ​​passadas entre o texto de uma tag, usamos a sintaxe # {variableName}. Por exemplo, no exemplo acima, se quisermos inserir Greetings from TutorialsPoint, teremos que usar o código a seguir.

html
   head
      title = name
   body
      h1 Greetings from #{name}
      a(href = url) URL

Este método de usar valores é chamado de interpolação.

Condicionais

Podemos usar instruções condicionais e construções de loop também. Considere este exemplo prático, se um usuário estiver logado, gostaríamos de exibir "Olá, usuário" e, se não, exibiríamos a ele um link "Login / Inscreva-se". Para conseguir isso, podemos definir um modelo simples, como -

html
   head
      title Simple template
   body
      if(user)
         h1 Hi, #{user.name}
      else
         a(href = "/sign_up") Sign Up

Quando renderizamos isso usando nossas rotas, e se passarmos por um objeto como -

this.render('/dynamic',{user: 
   {name: "Ayush", age: "20"}
});

Vai dar uma mensagem exibindo Oi, Ayush. No entanto, se não passarmos nenhum objeto ou passarmos um sem chave de usuário, obteremos um link de inscrição.

Incluir e componentes

O Pug fornece uma maneira muito intuitiva de criar componentes para uma página da web. Por exemplo, se você vir um site de notícias, o cabeçalho com logotipo e categorias é sempre fixo. Em vez de copiar isso para todas as visualizações, podemos usar um include. O exemplo a seguir mostra como podemos usar um include -

Crie três visualizações com o seguinte código -

header.pug

div.header.
   I'm the header for this website.

content.pug

html
   head
      title Simple template
   body
      include ./header.pug
      h3 I'm the main content
      include ./footer.pug

footer.pug

div.footer.
   I'm the footer for this website.

Crie uma rota para isso da seguinte maneira.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var Pug = require('koa-pug');
var pug = new Pug({
   viewPath: './views',
   basedir: './views',
   app: app //Equivalent to app.use(pug)
});

var _ = router(); //Instantiate the router

_.get('/components', getComponents);

function *getComponents(){
   this.render('content.pug');
}

app.use(_.routes()); //Use the routes defined using the router
app.listen(3000);

Vamos para localhost:3000/components, você deve obter a seguinte saída.

include também pode ser usado para incluir texto simples, CSS e JavaScript.

Existem muitas outras características do Pug. No entanto, eles estão fora do escopo deste tutorial. Você pode explorar mais o Pug em Pug .

Os formulários são parte integrante da web. Quase todos os sites que visitamos nos oferecem formulários que enviam ou buscam algumas informações para nós. Para começar com os formulários, primeiro instalaremos o koa-body. Para instalar isso, vá para o seu terminal e use -

$ npm install --save koa-body

Substitua o conteúdo do arquivo app.js pelo código a seguir.

var koa = require('koa');
var router = require('koa-router');
var bodyParser = require('koa-body');
var app = koa();

//Set up Pug
var Pug = require('koa-pug');
var pug = new Pug({
   viewPath: './views',
   basedir: './views',
   app: app //Equivalent to app.use(pug)
});

//Set up body parsing middleware
app.use(bodyParser({
   formidable:{uploadDir: './uploads'},
   multipart: true,
   urlencoded: true
}));

_.get('/', renderForm);
_.post('/', handleForm);

function * renderForm(){
   this.render('form');
}
function *handleForm(){
   console.log(this.request.body);
   console.log(this.req.body);
   this.body = this.request.body; //This is where the parsed request is stored
}

app.use(_.routes()); 
app.listen(3000);

As novas coisas que estamos fazendo aqui são importar o analisador de corpo e o multer. Estamos usando o analisador de corpo para analisar solicitações de cabeçalho codificadas em json e x-www-form-url, enquanto usamos multer para analisar multipart / form-data.

Vamos criar um formulário html para testar isso! Crie um novo modo de exibição denominado form.pug com o código a seguir.

html
   head
      title Form Tester
   body
      form(action = "/", method = "POST")
         div
            label(for = "say") Say: 
            input(name = "say" value = "Hi")
         br
         div
            label(for = "to") To: 
            input(name = "to" value = "Koa form")
         br
         button(type = "submit") Send my greetings

Execute seu servidor usando -

nodemon index.js

Agora vá para localhost: 3000 / e preencha o formulário como quiser e envie. Você receberá a resposta como -

Dê uma olhada em seu console, ele mostrará o corpo de sua solicitação como um objeto JavaScript. Por exemplo -

o this.request.bodyobjeto contém seu corpo de solicitação analisado. Para usar os campos desse objeto, basta usá-los como objetos JS normais.

Essa é apenas uma forma de enviar uma solicitação. Existem muitas outras maneiras, mas essas são irrelevantes para abordar aqui, porque nosso aplicativo Koa tratará todas essas solicitações da mesma maneira. Para ler mais sobre as diferentes maneiras de fazer uma solicitação, dê uma olhada nesta página.

Os aplicativos da Web precisam fornecer a funcionalidade para permitir o upload de arquivos. Vamos ver como podemos receber arquivos dos clientes e armazená-los em nosso servidor.

Já usamos o middleware koa-body para analisar solicitações. Este middleware também é usado para lidar com uploads de arquivos. Vamos criar um formulário que nos permite fazer upload de arquivos e salvá-los usando Koa. Primeiro crie um modelo chamadofile_upload.pug com o seguinte conteúdo.

html
   head
      title File uploads
   body
      form(action = "/upload" method = "POST" enctype = "multipart/form-data")
         div
            input(type = "text" name = "name" placeholder = "Name")
         
         div
            input(type = "file" name = "image")
         
         div
            input(type = "submit")

Observe que você precisa fornecer o mesmo tipo de codificação acima em seu formulário. Agora vamos lidar com esses dados em nosso servidor.

var koa = require('koa');
var router = require('koa-router');
var bodyParser = require('koa-body');
var app = koa();

//Set up Pug
var Pug = require('koa-pug');
var pug = new Pug({
   viewPath: './views',
   basedir: './views',
   app: app 
});

//Set up body parsing middleware
app.use(bodyParser({
   formidable:{uploadDir: './uploads'},    //This is where the files would come
   multipart: true,
   urlencoded: true
}));

var _ = router(); //Instantiate the router

_.get('/files', renderForm);
_.post('/upload', handleForm);

function * renderForm(){
   this.render('file_upload');
}

function *handleForm(){
   console.log("Files: ", this.request.body.files);
   console.log("Fields: ", this.request.body.fields);
   this.body = "Received your data!"; //This is where the parsed request is stored
}

app.use(_.routes()); 
app.listen(3000);

Ao executar isso, você obtém o seguinte formulário.

Quando você enviar isso, seu console produzirá a seguinte saída.

Os arquivos carregados são armazenados no caminho da saída acima. Você pode acessar os arquivos na solicitação usandothis.request.body.files e os campos dessa solicitação por this.request.body.fields.

Os arquivos estáticos são arquivos que os clientes baixam quando estão no servidor. Crie um novo diretório,public. Express, por padrão, não permite que você forneça arquivos estáticos.

Precisamos de um middleware para atender a esse propósito. Vá em frente e instalekoa-serve -

$ npm install --save koa-static

Agora precisamos useeste middleware. Antes disso, crie um diretório chamado public. Armazenaremos todos os nossos arquivos estáticos aqui. Isso nos permite manter nosso código de servidor seguro, pois nada acima desta pasta pública seria acessível aos clientes. Depois de criar um diretório público, crie um arquivo chamadohello.txtnele com qualquer conteúdo que você gosta. Agora adicione o seguinte ao seu app.js.

var serve = require('koa-static');
var koa = require('koa');
var app = koa();

app.use(serve('./public'));

app.listen(3000);

Note- Koa procura os arquivos relativos ao diretório estático, portanto, o nome do diretório estático não faz parte da URL. A rota raiz está agora definida para seu diretório público, então todos os arquivos estáticos que você carregar serão considerados públicos como raiz. Para testar se isso está funcionando bem, execute seu aplicativo e visitehttps://localhost:3000/hello.txt

Você deve obter a seguinte saída. Observe que este não é um documento HTML ou visão Pug, mas sim um simples arquivo txt.

Multiple Static Dirs

Também podemos definir vários diretórios de ativos estáticos usando -

var serve = require('koa-static');
var koa = require('koa');
var app = koa();

app.use(serve('./public'));
app.use(serve('./images'));

app.listen(3000);

Agora, quando solicitarmos um arquivo, Koa pesquisará esses diretórios e nos enviará o arquivo correspondente.

Cookies são arquivos / dados simples e pequenos que são enviados ao cliente com uma solicitação do servidor e armazenados no lado do cliente. Cada vez que o usuário carrega o site de volta, este cookie é enviado com a solicitação. Isso ajuda a monitorar as ações dos usuários. Existem vários usos de cookies HTTP.

  • Gerenciamento de sessão
  • Personalização (sistemas de recomendação)
  • Rastreamento de usuário

Para usar cookies com Koa, temos as funções: ctx.cookies.set() e ctx.cookies.get(). Para definir um novo cookie, vamos definir uma nova rota em nosso aplicativo Koa.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

_.get('/', setACookie);

function *setACookie() {
   this.cookies.set('foo', 'bar', {httpOnly: false});
}

var _ = router();

app.use(_.routes());
app.listen(3000);

Para verificar se o cookie está definido ou não, basta ir ao seu navegador, iniciar o console e inserir -

console.log(document.cookie);

Isso produzirá a seguinte saída (você pode ter mais cookies definidos, talvez devido a extensões em seu navegador).

"foo = bar"

Aqui está um exemplo do acima.

O navegador também envia cookies de volta toda vez que consulta o servidor. Para visualizar um cookie em seu servidor, no console do servidor em uma rota, adicione o seguinte código a essa rota.

console.log('Cookies: foo = ', this.cookies.get('foo'));

Na próxima vez que você enviar uma solicitação para esta rota, obterá a seguinte saída.

Cookies: foo = bar

Adicionando Cookies com Tempo de Expiração

Você pode adicionar cookies que expiram. Para adicionar um cookie que expira, basta passar um objeto com a propriedade 'expira' definida para a hora em que deseja que ele expire. Por exemplo,

var koa = require('koa');
var router = require('koa-router');
var app = koa();

_.get('/', setACookie);

function *setACookie(){
   //Expires after 360000 ms from the time it is set.
	this.cookies.set('name', 'value', { 
      httpOnly: false, expires: 360000 + Date.now() });
}

var _ = router();

app.use(_.routes());
app.listen(3000);

Excluindo Cookies Existentes

Para remover um cookie, simplesmente defina o cookie como uma string vazia. Por exemplo, se você precisar limpar um cookie chamadofoo, use o código a seguir.

var koa = require('koa');
var router = require('koa-router');
var app = koa();

_.get('/', setACookie);

function *setACookie(){
   //Expires after 360000 ms from the time it is set.
   this.cookies.set('name', '');
}

var _ = router();

app.use(_.routes());
app.listen(3000);

Isso irá remover a definição do referido cookie. Observe que você deve deixar oHttpOnly opção para ser verdadeira quando não usar o cookie no código do lado do cliente.

O HTTP não tem estado, portanto, para associar uma solicitação a qualquer outra solicitação, você precisa de uma maneira de armazenar dados do usuário entre as solicitações HTTP. Cookies e parâmetros de URL são maneiras adequadas de transportar dados entre o cliente e o servidor. No entanto, ambos são legíveis no lado do cliente. As sessões resolvem exatamente esse problema. Você atribui um ID ao cliente e ele faz todas as solicitações adicionais usando esse ID. As informações associadas ao cliente são armazenadas no servidor vinculado a este ID.

Precisaremos da sessão koa, portanto, instale-a usando -

npm install --save koa-session

Vamos colocar o koa-sessionmiddleware instalado. Neste exemplo, usaremos a RAM para armazenar sessões. Nunca use isso em ambientes de produção. O middleware de sessão trata de tudo, ou seja, criar a sessão, definir o cookie da sessão e criar o objeto de sessão no objeto de contexto.

Sempre que voltarmos a fazer um pedido ao mesmo cliente, teremos as suas informações de sessão armazenadas connosco (visto que o servidor não foi reiniciado). Podemos adicionar mais propriedades a este objeto de sessão. No exemplo a seguir, criaremos um contador de visualizações para um cliente.

var session = require('koa-session');
var koa = require('koa');
var app = koa();

app.keys = ['Shh, its a secret!'];
app.use(session(app));  // Include the session middleware

app.use(function *(){
   var n = this.session.views || 0;
   this.session.views = ++n;
   
   if(n === 1)
      this.body = 'Welcome here for the first time!';
   else
      this.body = "You've visited this page " + n + " times!";
})

app.listen(3000);

O que o código acima faz é, quando um usuário visita o site, ele cria uma nova sessão para o usuário e atribui um cookie. Na próxima vez que o usuário visitar, o cookie será verificado e a variável de sessão page_view será atualizada de acordo.

Agora, se você executar o aplicativo e for para localhost:3000, você obterá a seguinte resposta.

Se você revisitar a página, o contador de páginas aumentará. Nesse caso, a página foi atualizada 12 vezes.

A autenticação é um processo no qual as credenciais fornecidas são comparadas àquelas armazenadas no banco de dados de informações de usuários autorizados em um sistema operacional local ou em um servidor de autenticação. Se as credenciais corresponderem, o processo será concluído e o usuário receberá autorização de acesso.

Estaremos criando um sistema de autenticação muito básico que usará Basic HTTP Authentication. Esta é a maneira mais simples possível de impor o controle de acesso, pois não requer cookies, sessões ou qualquer outra coisa. Para usar isso, o cliente deve enviar o cabeçalho de autorização junto com todas as solicitações feitas. O nome de usuário e a senha não são criptografados, mas são concatenados em uma única string como a seguir.

username:password

Essa string é codificada com Base64 e a palavra Basic é colocada antes desse valor. Por exemplo, se seu nome de usuário for Ayush e senha Índia, então a string"Ayush:India" seria enviado codificado no cabeçalho de autorização.

Authorization: Basic QXl1c2g6SW5kaWE=

Para implementar isso em seu aplicativo koa, você precisará do middleware koa-basic-auth. Instale-o usando -

$ npm install --save koa-basic-auth

Agora abra seu arquivo app.js e insira o seguinte código nele.

//This is what the authentication would be checked against
var credentials = { name: 'Ayush', pass: 'India' }

var koa = require('koa');
var auth = require('koa-basic-auth');
var _ = require('koa-router')();

var app = koa();

//Error handling middleware
app.use(function *(next){
   try {
      yield next;
   } catch (err) {
      if (401 == err.status) {
         this.status = 401;
         this.set('WWW-Authenticate', 'Basic');
         this.body = 'You have no access here';
      } else {
         throw err;
      }
   }
});

// Set up authentication here as first middleware. 
// This returns an error if user is not authenticated.
_.get('/protected', auth(credentials), function *(){
   this.body = 'You have access to the protected area.';
   yield next;
});

// No authentication middleware present here.
_.get('/unprotected', function*(next){
   this.body = "Anyone can access this area";
   yield next;
});

app.use(_.routes());
app.listen(3000);

Criamos um middleware de tratamento de erros para tratar todos os erros relacionados à autenticação. Então, criamos 2 rotas -

  • /protected- Esta rota só pode ser acessada se o usuário enviar o cabeçalho de autenticação correto. Para todos os outros, apresentará um erro.

  • /unprotected - Esta rota pode ser acessada por qualquer pessoa, com ou sem a autenticação.

Agora, se você enviar uma solicitação para / protected sem um cabeçalho de autenticação ou com as credenciais erradas, você receberá um erro. Por exemplo,

$ curl https://localhost:3000/protected

Você receberá a resposta como -

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic
Content-Type: text/plain; charset=utf-8
Content-Length: 28
Date: Sat, 17 Sep 2016 19:05:56 GMT
Connection: keep-alive

Please authenticate yourself

No entanto, com as credenciais certas, você obterá a resposta esperada. Por exemplo,

$ curl -H "Authorization: basic QXl1c2g6SW5kaWE=" https://localhost:3000/protected -i

Você receberá a resposta como -

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 38
Date: Sat, 17 Sep 2016 19:07:33 GMT
Connection: keep-alive

You have access to the protected area.

A rota / desprotegida ainda é acessível a todos.

A compactação é uma maneira simples e eficaz de economizar largura de banda e acelerar seu site. Ele só é compatível com navegadores modernos e deve ser usado com cuidado se os usuários também usarem navegadores legados.

Ao enviar respostas do servidor, se a compactação for usada, ela pode melhorar muito o tempo de carregamento. Estaremos usando um middleware chamadokoa-compress para cuidar da compactação de arquivos, bem como definir os cabeçalhos apropriados.

Vá em frente e instale o middleware usando -

$ npm install --save koa-compress

Agora, em seu arquivo app.js, adicione o seguinte código -

var koa = require('koa');
var router = require('koa-router');
var app = koa();

var Pug = require('koa-pug');
var pug = new Pug({
   viewPath: './views',
   basedir: './views',
   app: app //Equivalent to app.use(pug)
});

app.use(compress({
   filter: function (content_type) {
      return /text/i.test(content_type)
   },
   threshold: 2048,
   flush: require('zlib').Z_SYNC_FLUSH
}));

var _ = router(); //Instantiate the router

_.get('/', getRoot);

function *getRoot(next){
   this.render('index');
}

app.use(_.routes()); //Use the routes defined using the router
app.listen(3000);

Isso coloca nosso middleware de compactação no lugar. A opção de filtro é uma função que verifica o tipo de conteúdo de resposta para decidir se deve compactar. A opção de limite é o tamanho mínimo de resposta em bytes para compactar. Isso garante que não compactemos cada pequena resposta.

A seguir está uma resposta sem compressão.

A seguir está a resposta semelhante com compactação.

Se você olhar para a guia de tamanho na parte inferior, poderá ver muito bem a diferença entre os dois. Há mais de 150% de melhoria, quando compactamos os arquivos.

Cache é o termo para armazenar respostas reutilizáveis ​​para tornar as solicitações subsequentes mais rápidas. Cada navegador vem com uma implementação de um cache HTTP. Tudo o que precisamos fazer é garantir que cada resposta do servidor forneça diretivas de cabeçalho HTTP corretas para instruir o navegador sobre quando e por quanto tempo a resposta pode ser armazenada em cache pelo navegador.

A seguir estão alguns benefícios de incluir o cache em seus aplicativos da web -

  • Seus custos de rede diminuem. Se seu conteúdo estiver em cache, você precisará enviar menos para cada solicitação subsequente.

  • A velocidade e o desempenho do seu site aumentam.

  • Seu conteúdo pode ser disponibilizado mesmo se seu cliente estiver offline.

Estaremos usando o middleware koa-static-cache para implementar o cache em nosso aplicativo. Instale este middleware usando -

$ npm install --save koa-static-cache

Vá para o arquivo app.js e adicione o código a seguir a ele.

var koa = require('koa');
var app = koa();

var path = require('path');
var staticCache = require('koa-static-cache');

app.use(staticCache(path.join(__dirname, 'public'), {
   maxAge: 365 * 24 * 60 * 60  //Add these files to caches for a year
}))

app.listen(3000);

o koa-static-cachemiddleware é usado para armazenar em cache as respostas do servidor no lado do cliente. ocache-controlo cabeçalho é definido de acordo com as opções que fornecemos ao inicializar o objeto de cache. Definimos o tempo de expiração desta resposta em cache para 1 ano. A seguir estão as comparações da solicitação enviada antes e depois do arquivo ser armazenado em cache.

Antes de esse arquivo ser armazenado em cache, o código de status retornado era 200, o que está OK. Os cabeçalhos de resposta tinham várias informações sobre o conteúdo a ser armazenado em cache e também forneciam umETag para o conteúdo.

Na próxima vez que a solicitação for enviada, ela será enviada junto com a ETtag. Como nosso conteúdo não mudou no servidor, sua ETag correspondente também permaneceu a mesma e o cliente foi informado de que a cópia que ele possui localmente está atualizada com o que o servidor forneceria e deveria usar a local em vez de solicitar novamente.

Note- Para invalidar qualquer arquivo em cache, basta alterar seu nome de arquivo e atualizar sua referência. Isso garantirá que você tenha um novo arquivo para enviar ao cliente e que o cliente não possa carregá-lo de volta do cache.

Estamos recebendo as solicitações, mas não as armazenamos em nenhum lugar. Precisamos de um banco de dados para armazenar os dados. Usaremos um banco de dados NoSQL famoso chamadoMongoDB. Para instalar e ler sobre o Mongo, acesse este link.

Para usar o Mongo com Koa, precisamos de uma API cliente para o nó. Existem várias opções para nós, no entanto, para este tutorial, nos limitaremos ao mangusto . Mongoose é usado paradocument modelingno Node para MongoDB. Modelagem de documentos significa que vamos criar umModel (muito parecido com um class na programação orientada a documentos), e então iremos produzir documents usando este modelo (como criamos documents of a classem OOP). Todo o nosso processamento será feito nestes "documentos", então finalmente, iremos escrever estes documentos em nosso banco de dados.

Configurando o Mongoose

Agora que temos o Mongo instalado, vamos instalar o mongoose, da mesma forma que instalamos nossos outros pacotes de nós.

$ npm install --save mongoose

Antes de começarmos a usar o mongoose, temos que criar um banco de dados usando o shell Mongo. Para criar um novo banco de dados, abra seu terminal e digite "mongo". Um shell Mongo será iniciado, digite o seguinte.

use my_db

Um novo banco de dados será criado para você. Sempre que você abrir o shell do Mongo, o padrão será "test" db e você terá que mudar para seu banco de dados usando o mesmo comando acima.

Para usar o mongoose, vamos exigi-lo em nosso arquivo app.js e, em seguida, conectar ao serviço mongod em execução em mongodb: // localhost

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');

app.use(_.routes());
app.listen(3000);

Agora que nosso aplicativo está conectado ao nosso banco de dados, vamos criar um novo modelo. Este modelo funcionará como uma coleção em nosso banco de dados. Para criar um novo modelo, use o seguinte código, antes de definir qualquer rota.

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');

var personSchema = mongoose.Schema({
   name: String,
   age: Number,
   nationality: String
});

var Person = mongoose.model("Person", personSchema);

app.use(_.routes());
app.listen(3000);

O código acima define o esquema para uma pessoa e é usado para criar um modelo de mangusto Person.

Salvando documentos

Agora vamos criar um novo formulário html, que vai pegar os detalhes de uma pessoa e salvá-lo em nosso banco de dados. Para criar o formulário, crie um novo arquivo de visualização denominado person.pug no diretório de visualizações com o seguinte conteúdo.

html
   head
      title Person
   body
      form(action = "/person", method = "POST")
         div
            label(for = "name") Name: 
            input(name = "name")
         br
         div
            label(for = "age") Age: 
            input(name = "age")
         br
         div
            label(for = "nationality") Nationality: 
            input(name = "nationality")
         br
         button(type = "submit") Create new person

Adicione também uma nova rota get em index.js para renderizar este documento.

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');

var personSchema = mongoose.Schema({
   name: String,
   age: Number,
   nationality: String
});

var Person = mongoose.model("Person", personSchema);

_.get('/person', getPerson);

function *getPerson(next){
   this.render('person');
   yield next;
}

app.use(_.routes());
app.listen(3000);

Vá para localhost: 3000 / person para verificar se nosso formulário está sendo exibido corretamente. Observe que isso é apenas a IU, ainda não está funcionando. Esta é a aparência do nosso formulário.

Agora definiremos um gerenciador de pós-rota em '/ pessoa' que tratará dessa solicitação.

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');

var personSchema = mongoose.Schema({
   name: String,
   age: Number,
   nationality: String
});

var Person = mongoose.model("Person", personSchema);

_.post('/person', createPerson);

function *createPerson(next){
   var self = this;
   var personInfo = self.request.body; //Get the parsed information
   
   if(!personInfo.name || !personInfo.age || !personInfo.nationality){
      self.render(
         'show_message', {message: "Sorry, you provided wrong info", type: "error"});
   } else {
      var newPerson = new Person({
         name: personInfo.name,
         age: personInfo.age,
         nationality: personInfo.nationality
      });
      yield newPerson.save(function(err, res) {
         if(err)
            self.render('show_message', 
               {message: "Database error", type: "error"});
         else
            self.render('show_message', 
               {message: "New person added", type: "success", person: personInfo});
      });
   }
}

app.use(_.routes());
app.listen(3000);

No código acima, se recebermos algum campo vazio ou não recebermos nenhum campo, enviaremos uma resposta de erro. No entanto, se recebermos um documento bem formado, então criamos um documento newPerson a partir do modelo Person e o salvamos em nosso banco de dados usandonewPerson.save()função. Isso é definido no mangusto e aceita um retorno de chamada como argumento. Este retorno de chamada tem dois argumentos,error e response. Isso irá renderizar a visualização show_message, então precisamos criá-la também.

Para mostrar a resposta dessa rota, também precisaremos criar um show_messageVisão. Crie uma nova visualização com o código a seguir.

html
   head
      title Person
   body
      if(type = "error")
         h3(style = "color:red") #{message}
      else
         h3 New person, name: 
            #{person.name}, age: 
            #{person.age} and nationality: 
            #{person.nationality} added!

A seguir está a resposta que recebemos ao enviar o formulário com sucesso (show_message.pug).

Agora temos uma interface para criar pessoas!

Recuperando Documentos

O Mongoose fornece muitas funções para recuperar documentos, vamos nos concentrar em três delas. Todas essas funções também recebem um retorno de chamada como o último parâmetro e, assim como a função salvar, seus argumentos são erro e resposta.

As três funções são -

Model.find (condições, retorno de chamada)

Esta função encontra todos os documentos correspondentes aos campos no objeto de condições. Os mesmos operadores usados ​​no Mongo também funcionam no mangusto. Por exemplo, isso irá buscar todos os documentos da coleção das pessoas.

Person.find(function(err, response){
   console.log(response);
});

Isso irá buscar todos os documentos onde o nome do campo é "Ayush" e a idade é 20.

Person.find({name: "Ayush", age: 20}, 
   function(err, response){
      console.log(response);
   });

Também podemos fornecer a projeção de que precisamos, ou seja, os campos de que precisamos. Por exemplo, se quisermos apenas onames das pessoas cujo nationalityé "indiano" , usamos -

Person.find({nationality: "Indian"}, 
   "name", function(err, response) {
      console.log(response);
   });

Model.findOne (condições, retorno de chamada)

Essa função sempre busca um único documento mais relevante. Ele tem os mesmos argumentos exatos que Model.find ().

Model.findById (id, callback)

Esta função leva no _id(definido por mongo) como o primeiro argumento, uma string de projeção opcional e um retorno de chamada para lidar com a resposta. Por exemplo,

Person.findById("507f1f77bcf86cd799439011", 
   function(err, response){
      console.log(response);
   });

Vamos criar uma rota para visualizar todos os registros de pessoas.

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');

var personSchema = mongoose.Schema({
   name: String,
   age: Number,
   nationality: String
});

var Person = mongoose.model("Person", personSchema);

_.get('/people', getPeople);
function *getPeople(next){
   var self = this;
   
   yield Person.find(function(err, response){
      self.body = response;
   });
}
app.use(_.routes());
app.listen(3000);

Atualizando Documentos

O Mongoose oferece três funções para atualizar documentos.

Model.update (condição, atualizações, retorno de chamada)

Essa função pega uma condição e atualiza o objeto como entrada e aplica as alterações a todos os documentos que correspondem às condições na coleção. Por exemplo, o código a seguir atualizará todos os documentos da pessoa para que tenham a nacionalidade "americana".

Person.update({age: 25},
   {nationality: "American"}, 
   function(err, response){
      console.log(response);
   });

Model.findOneAndUpdate (condição, atualizações, retorno de chamada)

Ele faz exatamente o que é dito. Encontra um documento com base na consulta e o atualiza de acordo com o segundo argumento. Também leva um retorno de chamada como último argumento. Por exemplo,

Person.findOneAndUpdate({name: "Ayush"}, 
   {age: 40}, 
   function(err, response){
      console.log(response);
   });

Model.findByIdAndUpdate (id, updates, callback)

Esta função atualiza um único documento identificado por seu id. Por exemplo,

Person.findByIdAndUpdate("507f1f77bcf86cd799439011", 
   {name: "James"}, 
   function(err, response){
      console.log(response);
   });

Vamos criar uma rota para atualizar as pessoas. Esta será uma rota PUT com o id como parâmetro e detalhes na carga útil.

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();
var mongoose = require('mongoose');

mongoose.connect('mongodb://localhost/my_db');

var personSchema = mongoose.Schema({
   name: String,
   age: Number,
   nationality: String
});

var Person = mongoose.model("Person", personSchema);

_.put('/people/:id', updatePerson);

function *updatePerson() {
   var self = this;
   yield Person.findByIdAndUpdate(self.params.id, 
      {$set: {self.request.body}}, function(err, response){
      
      if(err) {
         self.body = {
            message: "Error in updating person with id " + self.params.id};
      } else {
         self.body = response;
      }
   });
}

app.use(_.routes());
app.listen(3000);

Para testar esta rota, digite o seguinte em seu terminal (substitua o id por um id de seu povo criado).

curl -X PUT --data "name = James&age = 20&nationality = American" https://localhost:3000/people/507f1f77bcf86cd799439011

Isso atualizará o documento associado ao id fornecido na rota com os detalhes acima.

Apagando Documentos

Nós cobrimos Create, Read e Update, agora veremos como o mongoose pode ser usado para excluir documentos. Existem três funções aqui, exatamente como atualizar.

Model.remove (condição, [retorno de chamada])

Esta função recebe um objeto de condição como entrada e remove todos os documentos que atendem às condições. Por exemplo, se precisarmos remover todas as pessoas com 20 anos,

Person.remove({age:20});

Model.findOneAndRemove (condição, [retorno de chamada])

Esta função remove um single, documento mais relevante de acordo com o objeto de condições. Por exemplo,

Person.findOneAndRemove({name: "Ayush"});

Model.findByIdAndRemove (id, [callback])

Esta função remove um único documento identificado por seu id. Por exemplo,

Person.findByIdAndRemove("507f1f77bcf86cd799439011");

Agora vamos criar uma rota para deletar pessoas de nosso banco de dados.

var koa = require('koa');
var _ = require('koa-router')();
var app = koa();

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_db');

var personSchema = mongoose.Schema({
   name: String,
   age: Number,
   nationality: String
});

var Person = mongoose.model("Person", personSchema);

_.delete('/people/:id', deletePerson);
function *deletePerson(next){
   var self = this;
   yield Person.findByIdAndRemove(self.params.id, function(err, response){
      if(err) {
         self.body = {message: "Error in deleting record id " + self.params.id};
      } else {
         self.body = {message: "Person with id " + self.params.id + " removed."};
      }
   });
}

app.use(_.routes());
app.listen(3000);

Para testar isso, use o seguinte comando curl -

curl -X DELETE https://localhost:3000/people/507f1f77bcf86cd799439011

Isso removerá a pessoa com o id fornecido, produzindo a seguinte mensagem. -

{message: "Person with id 507f1f77bcf86cd799439011 removed."}

Isso conclui como podemos criar aplicativos CRUD simples usando MongoDB, mongoose e Koa. Para explorar mais o mangusto, leia a documentação da API.

Para criar aplicativos móveis, aplicativos de página única, usar chamadas AJAX e fornecer dados aos clientes, você precisará de uma API. Um estilo de arquitetura popular de como estruturar e nomear essas APIs e os terminais é chamadoREST(Representational Transfer State). HTTP 1.1 foi projetado mantendo os princípios REST em mente. REST foi introduzido porRoy Fielding em 2000 em seu artigo Fielding Dissertations.

URIs e métodos RESTful nos fornecem quase todas as informações de que precisamos para processar uma solicitação. A tabela a seguir resume como os vários verbos devem ser usados ​​e como os URIs devem ser nomeados. Estaremos criando uma API de filmes no final, então vamos discutir como ela será estruturada.

Método URI Detalhes Função
PEGUE /filmes Seguro, encaixável Obtém a lista de todos os filmes e seus detalhes
PEGUE / movies / 1234 Seguro, encaixável Obtém os detalhes da identificação do filme 1234
POSTAR /filmes N / D Cria um novo filme com os detalhes fornecidos. A resposta contém o URI para este recurso recém-criado.
COLOCAR / movies / 1234 Idempotente Modifica o ID do filme 1234 (cria um se ainda não existir). A resposta contém o URI para este recurso recém-criado.
EXCLUIR / movies / 1234 Idempotente A identificação do filme 1234 deve ser excluída, se existir. A resposta deve conter o status da solicitação.
DELETE ou PUT /filmes Inválido Deve ser inválido. DELETE e PUT devem especificar em qual recurso estão trabalhando.

Agora vamos criar essa API no Koa. Usaremos JSON como nosso formato de transporte de dados, pois é fácil de trabalhar em JavaScript e tem muitos outros benefícios. Substitua seu arquivo index.js pelo seguinte -

INDEX.JS

var koa = require('koa');
var router = require('koa-router');
var bodyParser = require('koa-body');

var app = koa();

//Set up body parsing middleware
app.use(bodyParser({
   formidable:{uploadDir: './uploads'},
   multipart: true,
   urlencoded: true
}));

//Require the Router we defined in movies.js
var movies = require('./movies.js');

//Use the Router on the sub route /movies
app.use(movies.routes());

app.listen(3000);

Agora que nosso aplicativo está configurado, vamos nos concentrar na criação da API. Primeiro configure o arquivo movies.js. Não estamos usando um banco de dados para armazenar os filmes, mas sim na memória, portanto, toda vez que o servidor reiniciar, os filmes adicionados por nós desaparecerão. Isso pode ser facilmente imitado usando um banco de dados ou um arquivo (usando o módulo node fs).

Importe o roteador koa, crie um roteador e exporte-o usando module.exports.

var Router = require('koa-router');
var router = Router({
  prefix: '/movies'
});  //Prefixed all routes with /movies

var movies = [
   {id: 101, name: "Fight Club", year: 1999, rating: 8.1},
   {id: 102, name: "Inception", year: 2010, rating: 8.7},
   {id: 103, name: "The Dark Knight", year: 2008, rating: 9},
   {id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];

//Routes will go here

module.exports = router;

Rotas GET

Defina a rota GET para obter todos os filmes.

router.get('/', sendMovies);
function *sendMovies(next){
   this.body = movies;
   yield next;
}

É isso aí. Para testar se está funcionando bem, execute seu aplicativo, abra o terminal e digite -

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET localhost:3000/movies

Você obterá a seguinte resposta -

[{"id":101,"name":"Fight 
Club","year":1999,"rating":8.1},{"id":102,"name":"Inception","year":2010,"rating":8.7},
{"id":103,"name":"The Dark Knight","year":2008,"rating":9},{"id":104,"name":"12 Angry 
Men","year":1957,"rating":8.9}]

Temos uma rota para obter todos os filmes. Agora vamos criar uma rota para obter um filme específico por seu id.

router.get('/:id([0-9]{3,})', sendMovieWithId);

function *sendMovieWithId(next){
   var ctx = this;
   var currMovie = movies.filter(function(movie){
      if(movie.id == ctx.params.id){
         return true;
      }
   });
   if(currMovie.length == 1){
      this.body = currMovie[0];
   } else {
      this.response.status = 404;//Set status to 404 as movie was not found
      this.body = {message: "Not Found"};
   }
   yield next;
}

Isso nos dará os filmes de acordo com a id que fornecemos. Para testar isso, use o seguinte comando em seu terminal.

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET localhost:3000/movies/101

Você receberá a resposta como -

{"id":101,"name":"Fight Club","year":1999,"rating":8.1}

Se você visitar uma rota inválida, produzirá um erro não é possível GET, enquanto se você visitar uma rota válida com um id que não existe, produzirá um erro 404.

Terminamos com as rotas GET. Agora, vamos passar para a rota POST.

POST Route

Use a seguinte rota para lidar com os dados POSTADOS.

router.post('/', addNewMovie);

function *addNewMovie(next){
   //Check if all fields are provided and are valid:
   if(!this.request.body.name || 
      !this.request.body.year.toString().match(/^[0-9]{4}$/g) || 
      !this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
      
      this.response.status = 400;
      this.body = {message: "Bad Request"};
   } else {
      var newId = movies[movies.length-1].id+1;
      
      movies.push({
         id: newId,
         name: this.request.body.name,
         year: this.request.body.year,
         rating: this.request.body.rating
      });
      this.body = {message: "New movie created.", location: "/movies/" + newId};
   }
   yield next;
}

Isso criará um novo filme e o armazenará na variável movies. Para testar esta rota, digite o seguinte em seu terminal -

curl -X POST --data "name = Toy%20story&year = 1995&rating = 8.5" 
https://localhost:3000/movies

Você obterá a seguinte resposta -

{"message":"New movie created.","location":"/movies/105"}

Para testar se isso foi adicionado ao objeto movies, execute a solicitação get para / movies / 105 novamente. Você obterá a seguinte resposta -

{"id":105,"name":"Toy story","year":"1995","rating":"8.5"}

Vamos prosseguir para criar as rotas PUT e DELETE.

PUT Rota

A rota PUT é quase exatamente igual à rota POST. Estaremos especificando o id do objeto que será atualizado / criado. Crie a rota da seguinte maneira -

router.put('/:id', updateMovieWithId);

function *updateMovieWithId(next){
   //Check if all fields are provided and are valid:
   if(!this.request.body.name || 
      !this.request.body.year.toString().match(/^[0-9]{4}$/g) || 
      !this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
      !this.params.id.toString().match(/^[0-9]{3,}$/g)){
      
      this.response.status = 400;
      this.body = {message: "Bad Request"};
   } else {
      //Gets us the index of movie with given id.
      var updateIndex = movies.map(function(movie){
         return movie.id;
      }).indexOf(parseInt(this.params.id));
      
      if(updateIndex === -1){
         //Movie not found, create new movies.push({
            id: this.params.id,
            name: this.request.body.name,
            year: this.request.body.year,
            rating: this.request.body.rating
         });
         this.body = {message: "New movie created.", location: "/movies/" + this.params.id};    
      } else {
         //Update existing movie
         movies[updateIndex] = {
            id: this.params.id,
            name: this.request.body.name,
            year: this.request.body.year,
            rating: this.request.body.rating
         };
         this.body = {message: "Movie id " + this.params.id + " updated.", location: "/movies/" + this.params.id};
      }
   }
}

Esta rota fará a função que especificamos na tabela acima. Ele atualizará o objeto com novos detalhes, se existir. Se não existir, ele criará um novo objeto. Para testar essa rota, use o seguinte comando curl. Isso irá atualizar um filme existente. Para criar um novo filme, basta alterar o id para um id não existente.

curl -X PUT --data "name = Toy%20story&year = 1995&rating = 8.5" 
https://localhost:3000/movies/101

Resposta

{"message":"Movie id 101 updated.","location":"/movies/101"}

DELETE rota

Use o seguinte código para criar uma rota de exclusão.

router.delete('/:id', deleteMovieWithId);

function *deleteMovieWithId(next){
   var removeIndex = movies.map(function(movie){
      return movie.id;
   }).indexOf(this.params.id); //Gets us the index of movie with given id.
   
   if(removeIndex === -1){
      this.body = {message: "Not found"};
   } else {
      movies.splice(removeIndex, 1);
      this.body = {message: "Movie id " + this.params.id + " removed."};
   }
}

Teste a rota da mesma forma que fizemos com as outras. Na exclusão bem-sucedida (por exemplo, id 105), você obterá -

{message: "Movie id 105 removed."}

Finalmente, nosso arquivo movies.js se parece com -

var Router = require('koa-router');
var router = Router({
   prefix: '/movies'
});  //Prefixed all routes with /movies
var movies = [
   {id: 101, name: "Fight Club", year: 1999, rating: 8.1},
   {id: 102, name: "Inception", year: 2010, rating: 8.7},
   {id: 103, name: "The Dark Knight", year: 2008, rating: 9},
   {id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];

//Routes will go here
router.get('/', sendMovies);
router.get('/:id([0-9]{3,})', sendMovieWithId);
router.post('/', addNewMovie);
router.put('/:id', updateMovieWithId);
router.delete('/:id', deleteMovieWithId);

function *deleteMovieWithId(next){
   var removeIndex = movies.map(function(movie){
      return movie.id;
   }).indexOf(this.params.id); //Gets us the index of movie with given id.
   
   if(removeIndex === -1){
      this.body = {message: "Not found"};
   } else {
      movies.splice(removeIndex, 1);
      this.body = {message: "Movie id " + this.params.id + " removed."};
   }
}

function *updateMovieWithId(next) {
   //Check if all fields are provided and are valid:
   if(!this.request.body.name ||
      !this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
      !this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
      !this.params.id.toString().match(/^[0-9]{3,}$/g)){
      
      this.response.status = 400;
      this.body = {message: "Bad Request"};
   } else {
      //Gets us the index of movie with given id.
      var updateIndex = movies.map(function(movie){
         return movie.id;
      }).indexOf(parseInt(this.params.id));
      
      if(updateIndex === -1){
         //Movie not found, create new
         movies.push({
            id: this.params.id,
            name: this.request.body.name,
            year: this.request.body.year,
            rating: this.request.body.rating
         });
         this.body = {message: "New movie created.", location: "/movies/" + this.params.id};
      } else {
         //Update existing movie
            movies[updateIndex] = {
            id: this.params.id,
            name: this.request.body.name,
            year: this.request.body.year,
            rating: this.request.body.rating
         };
         this.body = {message: "Movie id " + this.params.id + " updated.", 
            location: "/movies/" + this.params.id};
      }
   }
}

function *addNewMovie(next){
   //Check if all fields are provided and are valid:
   if(!this.request.body.name ||
      !this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
      !this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
      
      this.response.status = 400;
      this.body = {message: "Bad Request"};
   } else {
      var newId = movies[movies.length-1].id+1;
      
      movies.push({
         id: newId,
         name: this.request.body.name,
         year: this.request.body.year,
         rating: this.request.body.rating
      });
      this.body = {message: "New movie created.", location: "/movies/" + newId};
   }
   yield next;
}
function *sendMovies(next){
   this.body = movies;
   yield next;
}
function *sendMovieWithId(next){
   var ctx = this
   
   var currMovie = movies.filter(function(movie){
      if(movie.id == ctx.params.id){
         return true;
      }
   });
   if(currMovie.length == 1){
      this.body = currMovie[0];
   } else {
      this.response.status = 404;//Set status to 404 as movie was not found
      this.body = {message: "Not Found"};
   }
   yield next;
}
module.exports = router;

Isso conclui nossa API REST. Agora você pode criar aplicativos muito mais complexos usando este estilo de arquitetura simples e Koa.

O registro é muito útil ao criar aplicativos da web, pois eles nos dizem onde exatamente as coisas deram errado. Também entendemos o contexto das coisas que deram errado e podemos propor soluções possíveis para as mesmas.

Para habilitar o registro no Koa, precisamos do middleware, koa-logger. Instale-o usando o seguinte comando.

$ npm install --save-dev koa-logger

Agora, em seu aplicativo, adicione o código a seguir para habilitar o registro.

var logger = require('koa-logger')
var koa = require('koa')

var app = koa()
app.use(logger())

app.use(function*(){
   this.body = "Hello Logger";
})

app.listen(3000)

Execute este servidor e visite qualquer rota no servidor. Você deve ver os registros como -

Agora, se você receber um erro em uma rota ou solicitação específica, esses logs devem ajudá-lo a descobrir o que deu errado em cada um deles.

O andaime nos permite criar facilmente um skeleton for a web application. Criamos manualmente nosso diretório público, adicionamos middleware, criamos arquivos de rota separados, etc. Uma ferramenta de scaffolding configura todas essas coisas para que possamos começar diretamente a construir nosso aplicativo.

O scaffolder que usaremos é chamado Yeoman. É uma ferramenta de scaffolding construída para Node.js, mas também tem geradores para vários outros frameworks (como flask, rails, django, etc.). Para instalar o yeoman, digite o seguinte comando em seu terminal.

$ npm install -g yeoman

Yeoman usa geradores para criar aplicativos. Para verificar os geradores disponíveis no npm para usar com o yeoman, vá até aqui . Para o propósito deste tutorial, usaremos o 'generator-koa'. Para instalar este gerador, digite o seguinte comando em seu terminal.

$ npm install -g generator-koa

Para usar este gerador, digite -

yo koa

Em seguida, ele criará uma estrutura de diretório e criará os seguintes arquivos para você. Ele também instalará os módulos npm e componentes do bower necessários para você.

create package.json
create test/routeSpec.js
create views/layout.html
create views/list.html
create public/styles/main.css
create public/scripts/.gitkeep
create controllers/messages.js
create app.js
create .editorconfig
create .jshintrc

I'm all done. Running npm install & bower install for you to install 
the required dependencies. 
If this fails, try running the command yourself.

Este gerador cria uma estrutura muito simples para nós.

.
├── controllers
│   └── messages.js
├── public
|   ├── scripts
|   └── styles
|       └── main.css    
├── test
|   └── routeSpec.js
├── views
|   ├── layout.html
|   └── list.html
├── .editorconfig
├── .jshintrc
├── app.js
└── package.json

Explore os muitos geradores disponíveis para Koa e escolha o que mais se adapta a você. As etapas para trabalhar com todos os geradores são as mesmas. Você precisará instalar um gerador, executá-lo usando o yeoman, ele fará algumas perguntas e, em seguida, criará um esqueleto para seu aplicativo com base em suas respostas.

A seguir está uma lista de recursos que usamos durante o desenvolvimento deste tutorial -

  • Koajs.com

  • Koajs - Exemplos Uma lista de exemplos criada pela comunidade

  • Lista de middlewares oficiais e de terceiros .

  • Uma API CRUD usando koa.js - um screencast curto que passa pela criação de uma API CRUD em Koa.js

  • Screencast de início rápido de Koa.js

  • Introdução ao Koa.js e geradores