Koa.js - Guida rapida

Un framework per applicazioni Web fornisce una semplice API per creare siti Web, app Web e backend. Non devi preoccuparti di protocolli di basso livello, processi, ecc.

Cos'è Koa?

Koa fornisce un'interfaccia minima per creare applicazioni. È un framework molto piccolo (600 LoC) che fornisce gli strumenti necessari per creare app ed è abbastanza flessibile. Ci sono numerosi moduli disponibili su npm per Koa, che possono essere collegati direttamente ad esso. Koa può essere pensato come il nucleo di express.js senza tutti i campanelli e fischietti.

Perché Koa?

Koa ha un ingombro ridotto (600 LoC) ed è uno strato molto sottile di astrazione sul nodo per creare app lato server. È completamente collegabile e ha una vasta comunità. Questo ci permette anche di estendere facilmente Koa e usarlo in base alle nostre esigenze. È costruito utilizzando la tecnologia all'avanguardia (ES6) che gli conferisce un vantaggio rispetto ai framework più vecchi come Express.

Pug

Pug (precedentemente noto come Jade) è un linguaggio conciso per scrivere modelli HTML.

  • Produce HTML
  • Supporta il codice dinamico
  • Supporta la riusabilità (DRY)

È uno dei linguaggi di modellazione più popolari usati con Koa.

MongoDB e Mongoose

MongoDB è un database di documenti open source progettato per facilitare lo sviluppo e il ridimensionamento. Useremo questo database per memorizzare i dati.

Mongoose è un'API client per node.js che semplifica l'accesso al nostro database dalla nostra applicazione Koa.

Per iniziare a sviluppare utilizzando il framework Koa, è necessario che siano installati Node e npm (node ​​package manager). Se non li hai già, vai alla configurazione del nodo per installare il nodo sul tuo sistema locale. Conferma che node e npm siano installati eseguendo i seguenti comandi nel tuo terminale.

$ node --version
$ npm --version

Dovresti ricevere un output simile a -

v5.0.0
3.5.2

Assicurati che la versione del tuo nodo sia superiore a 6.5.0. Ora che abbiamo impostato Node e npm, capiamo cosa è npm e come usarlo.

Node Package Manager (npm)

npm è il gestore di pacchetti per node. Il registro npm è una raccolta pubblica di pacchetti di codice open source per Node.js, app Web front-end, app mobili, robot, router e innumerevoli altre esigenze della comunità JavaScript. npm ci permette di accedere a tutti questi pacchetti e installarli localmente. Puoi sfogliare l'elenco dei pacchetti disponibili su npm su npmJS .

Come usare npm?

Esistono due modi per installare un pacchetto utilizzando npm: a livello globale e locale.

Globally- Questo metodo viene generalmente utilizzato per installare strumenti di sviluppo e pacchetti basati su CLI. Per installare un pacchetto a livello globale, utilizzare il seguente comando.

$ npm install -g <package-name>

Locally- Questo metodo viene generalmente utilizzato per installare framework e librerie. Un pacchetto installato localmente può essere utilizzato solo all'interno della directory in cui è installato. Per installare un pacchetto in locale, utilizzare lo stesso comando di cui sopra senza il -g bandiera.

$ npm install <package-name>

Ogni volta che creiamo un progetto utilizzando npm, dobbiamo fornire un file package.json, che contiene tutti i dettagli sul nostro progetto. npm ci rende facile impostare questo file. Impostiamo il nostro progetto di sviluppo.

Step 1 - Avvia il tuo terminale / cmd, crea una nuova cartella denominata hello-world e cd in essa -

Step 2 - Ora per creare il file package.json usando npm, usa quanto segue.

npm init

Ti chiederà le seguenti informazioni:

Continua a premere invio e inserisci il tuo nome nel campo "nome dell'autore".

Step 3- Ora che abbiamo impostato il nostro file package.json, installeremo Koa. Per installare Koa e aggiungerlo nel nostro file package.json, usa il seguente comando.

$ npm install --save koa

Per confermare che Koa è installato correttamente, eseguire il seguente comando.

$ ls node_modules #(dir node_modules for windows)

Tip - Il --save flag può essere sostituito da -Sbandiera. Questo flag assicura che Koa venga aggiunto come dipendenza al nostro file package.json. Questo ha un vantaggio, la prossima volta che avremo bisogno di installare tutte le dipendenze del nostro progetto, dobbiamo solo eseguire il comando npm install e troverà le dipendenze in questo file e le installerà per noi.

Questo è tutto ciò di cui abbiamo bisogno per iniziare lo sviluppo utilizzando il framework Koa. Per rendere il nostro processo di sviluppo molto più semplice, installeremo uno strumento da npm, nodemon. Ciò che fa questo strumento è che riavvia il nostro server non appena apportiamo una modifica a uno dei nostri file, altrimenti dobbiamo riavviare il server manualmente dopo ogni modifica del file. Per installare nodemon, utilizzare il seguente comando.

$ npm install -g nodemon

Ora siamo tutti pronti per tuffarci in Koa!

Una volta impostato lo sviluppo, è ora di iniziare a sviluppare la nostra prima app utilizzando Koa. Crea un nuovo file chiamatoapp.js e digita quanto segue.

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')
});

Salva il file, vai sul tuo terminale e digita.

$ nodemon app.js

Questo avvierà il server. Per testare questa app, apri il browser e vai ahttps://localhost:3000 e dovresti ricevere il seguente messaggio.

Come funziona questa app?

La prima riga importa Koa nel nostro file. Abbiamo accesso alla sua API tramite la variabile Koa. Lo usiamo per creare un'applicazione e assegnarla a var app.

app.use(function)- Questa funzione è un middleware, che viene chiamato ogni volta che il nostro server riceve una richiesta. Impareremo di più sul middleware nei capitoli successivi. La funzione di callback è un generatore, che vedremo nel prossimo capitolo. Il contesto di questo generatore è chiamato contesto in Koa. Questo contesto viene utilizzato per accedere e modificare gli oggetti richiesta e risposta. Stiamo impostando il corpo di questa risposta per essereHello world!.

app.listen(port, function)- Questa funzione associa e ascolta le connessioni sulla porta specificata. La porta è l'unico parametro richiesto qui. La funzione di callback viene eseguita, se l'app viene eseguita correttamente.

Una delle nuove funzionalità più interessanti di JavaScript ES6 è una nuova generazione di funzioni, chiamata generatore. Prima dei generatori, l'intero script veniva solitamente eseguito in un ordine dall'alto verso il basso, senza un modo semplice per interrompere l'esecuzione del codice e riprendere con lo stesso stack in seguito. I generatori sono funzioni dalle quali è possibile uscire e successivamente reinserirsi. Il loro contesto (associazioni di variabili) verrà salvato attraverso i rientri.

I generatori ci consentono di interrompere l'esecuzione del codice nel mezzo. Quindi, diamo un'occhiata a un semplice generatore.

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

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

Quando si esegue il codice sopra, il risultato sarà il seguente.

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

Diamo un'occhiata all'interno del codice sopra. Per prima cosa creiamo un generatore chiamatogenerator_func(). Abbiamo creato un'istanza di questa funzione dall'aspetto strano e l'abbiamo assegnata aitr. Poi abbiamo iniziato a chiamarenext() su questa variabile itr.

Chiamare next () avvia il generatore e funziona finché non raggiunge un rendimento. Quindi restituisce l'oggetto con valore e fatto, dove il valore ha il valore dell'espressione. Questa espressione può essere qualsiasi cosa. A questo punto, interrompe l'esecuzione. Anche in questo caso, quando chiamiamo questa funzione (next), il generatore riprende l'esecuzione dall'ultimo punto di snervamento con lo stato della funzione uguale al momento della pausa, fino al successivo punto di snervamento. Questo viene fatto fino a quando non ci sono più punti di rendimento nel codice.

Generatori in Koa

Allora perché stiamo discutendo di generatori in questo tutorial. Come forse ricorderai dal programma hello world, abbiamo utilizzato un filefunction* ()notazione per passare una richiamata a app.use (). Koa è un oggetto, che contiene una serie di funzioni del generatore di middleware, tutte composte ed eseguite in modo simile a uno stack su ogni richiesta. Koa implementa anche il downstream seguito dall'upstream del flusso di controllo.

Dai un'occhiata al seguente esempio per capirlo in modo migliore.

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);

Quando si esegue il codice precedente e si passa a https://localhost:3000/ otteniamo il seguente output sulla nostra console.

1
3
5
6
4
2

Questo è essenzialmente il modo in cui Koa usa i generatori. Ci consente di creare middleware compatto utilizzando questa proprietà e scrivere codice per funzionalità sia upstream che downstream, risparmiandoci così i callback.

I framework Web forniscono risorse come pagine HTML, script, immagini, ecc. In percorsi diversi. Koa non supporta i percorsi nel modulo principale. Dobbiamo utilizzare il modulo Koa-router per creare facilmente percorsi in Koa. Installa questo modulo utilizzando il seguente comando.

npm install --save koa-router

Ora che abbiamo installato Koa-router, diamo un'occhiata a un semplice esempio di percorso 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 eseguiamo la nostra applicazione e andiamo su localhost: 3000 / hello, il server riceve una richiesta get in route "/ hello". La nostra app Koa esegue la funzione di callback associata a questo percorso e invia "Hello World!" come risposta.

Possiamo anche avere più metodi diversi sullo stesso percorso. Per esempio,

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);

Per testare questa richiesta, apri il tuo terminale e usa cURL per eseguire la seguente richiesta

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

Un metodo speciale, all, è fornito da express per gestire tutti i tipi di metodi http su un percorso particolare utilizzando la stessa funzione. Per utilizzare questo metodo, prova quanto segue:

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

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

Ora possiamo definire percorsi; sono statici o fissi. Per utilizzare percorsi dinamici, dobbiamo fornire diversi tipi di percorsi. L'utilizzo di percorsi dinamici ci consente di passare parametri e processi basati su di essi. Di seguito è riportato un esempio di percorso dinamico.

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);

Per testarlo vai a https://localhost:3000/123. Otterrai la seguente risposta.

Puoi sostituire "123" nell'URL con qualsiasi altra cosa e si rifletterà nella risposta. Di seguito è riportato un esempio complesso di quanto sopra.

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);

Per testarlo vai a https://localhost:3000/things/tutorialspoint/12345.

Puoi usare il file this.paramsoggetto per accedere a tutti i parametri che passi nell'URL. Nota che i due precedenti hanno percorsi diversi. Non si sovrapporranno mai. Inoltre, se vuoi eseguire il codice quando ottieni "/ things", devi definirlo separatamente.

Percorsi con corrispondenza del modello

Puoi anche utilizzare regex per limitare la corrispondenza dei parametri URL. Supponiamo che tu abbia bisogno che l'id sia un numero lungo cinque cifre. È possibile utilizzare la seguente definizione di percorso.

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);

Nota che questo lo farà onlycorrisponde alle richieste che hanno un ID lungo 5 cifre. Puoi usare espressioni regolari più complesse per abbinare / convalidare i tuoi percorsi. Se nessuno dei tuoi percorsi corrisponde alla richiesta, riceverai un messaggio Non trovato come risposta.

Ad esempio, se definiamo gli stessi percorsi di cui sopra, su richiesta con un URL valido, otteniamo:

Il metodo HTTP viene fornito nella richiesta e specifica l'operazione che il client ha richiesto. La tabella seguente riassume i metodi HTTP comunemente usati.

Sr.No. Metodo e descrizione
1

GET

Il metodo GET richiede una rappresentazione della risorsa specificata. Le richieste che utilizzano GET dovrebbero solo recuperare i dati e non dovrebbero avere altri effetti.

2

POST

Il metodo POST richiede che il server accetti i dati racchiusi nella richiesta come un nuovo oggetto / entità della risorsa identificata dall'URI.

3

PUT

Il metodo PUT richiede che il server accetti i dati racchiusi nella richiesta come modifica dell'oggetto esistente identificato dall'URI. Se non esiste, il metodo PUT dovrebbe crearne uno.

4

DELETE

Il metodo DELETE richiede che il server elimini la risorsa specificata.

Questi sono i metodi HTTP più comuni. Per saperne di più su di loro, vai ahttps://www.tutorialspoint.com/http/http_methods.htm.

Un oggetto Koa Request è un'astrazione in cima all'oggetto vanilla request di node, fornendo funzionalità aggiuntive utili per lo sviluppo quotidiano del server HTTP. L'oggetto richiesta Koa è incorporato nell'oggetto contesto,this. Disconnettiamo l'oggetto richiesta ogni volta che riceviamo una richiesta.

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 esegui questo codice e vai a https://localhost:3000/hello, quindi riceverai la seguente risposta.

Sulla tua console, l'oggetto della richiesta verrà disconnesso.

{ 
   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' 
   }
}

Abbiamo accesso a molte proprietà utili della richiesta utilizzando questo oggetto. Vediamo alcuni esempi.

request.header

Fornisce tutte le intestazioni della richiesta.

request.method

Fornisce il metodo di richiesta (GET, POST, ecc.)

request.href

Fornisce l'URL completo della richiesta.

request.path

Fornisce il percorso della richiesta. Senza stringa di query e URL di base.

request.query

Fornisce la stringa di query analizzata. Ad esempio, se lo registriamo su una richiesta comehttps://localhost:3000/hello/?name=Ayush&age=20&country=India, quindi otterremo il seguente oggetto.

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

request.accepts (tipo)

Questa funzione restituisce vero o falso a seconda che le risorse richieste accettino il tipo di richiesta specificato.

Puoi leggere ulteriori informazioni sull'oggetto richiesta nella documentazione su Request .

Un oggetto Koa Response è un'astrazione sopra l'oggetto vanilla response di node, che fornisce funzionalità aggiuntive utili per lo sviluppo quotidiano del server HTTP. L'oggetto risposta Koa è incorporato nell'oggetto contesto,this. Disconnettiamo l'oggetto risposta ogni volta che riceviamo una richiesta.

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 esegui questo codice e vai a https://localhost:3000/hello quindi riceverai la seguente risposta.

Sulla tua console, l'oggetto della richiesta verrà disconnesso.

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

Lo stato e il messaggio vengono impostati automaticamente da Koa ma possono essere modificati da noi. Se non impostiamo il corpo della risposta, il codice di stato è impostato su 404. Una volta impostato il corpo della risposta, lo stato è impostato su 200 per impostazione predefinita. Possiamo ignorare esplicitamente questo comportamento.

Abbiamo accesso a molte proprietà utili della risposta utilizzando questo oggetto. Vediamo alcuni esempi:

response.header

Fornisce tutte le intestazioni di risposta.

response.status

Fornisce lo stato della risposta (200, 404, 500 e così via). Questa proprietà viene utilizzata anche per impostare lo stato della risposta.

response.message

Fornisce il messaggio di risposta. Questa proprietà viene utilizzata anche per impostare messaggi personalizzati con risposte. È associato a response.status.

risposta.corpo

Ottieni o imposta il corpo della risposta. Di solito, vi accediamo utilizzando l'oggetto contesto. Questo è solo un altro modo per accedervi. Il corpo potrebbe essere del tipo: String, Buffer, Stream, Object o Null.

response.type

Ottieni o imposta il tipo di contenuto della risposta corrente.

response.get (campo)

Questa funzione viene utilizzata per ottenere i valori delle intestazioni con campo valore senza distinzione tra maiuscole e minuscole.

response.set (campo, valore)

Questa funzione viene utilizzata per impostare un'intestazione sulla risposta utilizzando il campo e la coppia di valori.

response.remove (campo)

Questa funzione viene utilizzata per annullare l'impostazione di un'intestazione sulla risposta utilizzando un nome di campo.

Puoi leggere ulteriori informazioni sull'oggetto risposta nei documenti su Response .

Il reindirizzamento è molto importante durante la creazione di siti Web. Se viene richiesto un URL non valido o ci sono degli errori sul tuo server, dovresti reindirizzarli alle rispettive pagine di errore. I reindirizzamenti possono essere utilizzati anche per impedire alle persone di accedere alle aree riservate del tuo sito web.

Creiamo una pagina di errore e reindirizziamo a quella pagina ogni volta che qualcuno richiede un URL non valido.

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 eseguiamo questo codice e navighiamo su qualsiasi percorso diverso da / hello, verremo reindirizzati a / not_found. Abbiamo posizionato il middleware alla fine (chiamata della funzione app.use a questo middleware). Ciò garantisce di raggiungere finalmente il middleware e di inviare la risposta corrispondente. Di seguito sono riportati i risultati che vediamo quando eseguiamo il codice sopra.

Quando navighiamo verso https://localhost:3000/hello, otteniamo -

Se navighiamo verso qualsiasi altra rotta, otteniamo:

La gestione degli errori gioca un ruolo importante nella creazione di applicazioni web. Koa utilizza il middleware anche a questo scopo.

In Koa, aggiungi un middleware che lo fa try { yield next }come uno dei primi middleware. Se riscontriamo un errore a valle, torniamo alla clausola catch associata e gestiamo l'errore qui. Ad esempio:

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);

Abbiamo deliberatamente creato un errore nel codice precedente e stiamo gestendo l'errore nel blocco catch del nostro primo middleware. Questo viene quindi emesso alla nostra console e inviato come risposta al nostro client. Di seguito è riportato il messaggio di errore che otteniamo quando attiviamo questo errore.

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

In questo momento qualsiasi richiesta inviata al server risulterà in questo errore.

Le funzioni middleware sono funzioni che hanno accesso a context objecte la successiva funzione middleware nel ciclo richiesta-risposta dell'applicazione. Queste funzioni vengono utilizzate per modificare gli oggetti richiesta e risposta per attività come l'analisi dei corpi delle richieste, l'aggiunta di intestazioni delle risposte, ecc.'downstream', quindi far scorrere indietro il controllo 'upstream'. Questo effetto è chiamatocascading.

Di seguito è riportato un semplice esempio di una funzione middleware in azione.

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);

Il middleware di cui sopra viene chiamato per ogni richiesta sul server. Quindi, dopo ogni richiesta, riceveremo il seguente messaggio nella console.

A new request received at 1467267512545

Per limitarlo a una rotta specifica (e tutte le sue subroute), dobbiamo solo creare le rotte come abbiamo fatto per le rotte. In realtà sono solo questi middleware che gestiscono la nostra richiesta.

Per esempio,

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);

Ora, ogni volta che richiedi una sottopercentuale di "/ request", solo allora registrerà l'ora.

Ordine delle chiamate middleware

Una delle cose più importanti sul middleware in Koa è che l'ordine in cui sono scritti / inclusi nel file, è l'ordine in cui vengono eseguiti a valle. Non appena si raggiunge una dichiarazione di rendimento in un middleware, si passa al middleware successivo in linea, fino a raggiungere l'ultimo. Poi di nuovo iniziamo a tornare indietro e riprendere le funzioni dalle istruzioni yield.

Ad esempio, nel seguente frammento di codice, la prima funzione viene eseguita prima fino a resa, poi il secondo middleware fino a resa, quindi la terza. Dato che qui non abbiamo più middleware, iniziamo a tornare indietro, eseguendo in ordine inverso, ovvero terzo, secondo, primo. Questo esempio riassume come utilizzare il middleware in modo 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 visitiamo "/" dopo aver eseguito questo codice, sulla nostra console otterremo:

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.

Il diagramma seguente riassume ciò che sta realmente accadendo nell'esempio precedente.

Ora che sappiamo come creare il nostro middleware, parliamo di alcuni dei middleware creati dalla comunità più comunemente usati.

Middleware di terze parti

Un elenco di middleware di terze parti per Express è disponibile qui. Di seguito sono riportati alcuni dei middleware più comunemente utilizzati:

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

Discuteremo di più middleware nei capitoli successivi.

Pug è un motore di modelli. I motori di modellazione vengono utilizzati per rimuovere l'ingombro del codice del nostro server con HTML, concatenando le stringhe in modo selvaggio ai modelli HTML esistenti. Pug è un motore di creazione di modelli molto potente, che ha una varietà di funzionalità comefilters, includes, inheritance, interpolation, ecc. C'è molto da fare su questo.

Per usare Pug con Koa, dobbiamo installarlo utilizzando il seguente comando.

$ npm install --save pug koa-pug

Una volta installato pug, impostalo come motore di modelli per la tua app. Aggiungi il codice seguente al tuo file 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);

Ora crea una nuova directory chiamata views. All'interno della directory, crea un file denominato first_view.pug e inserisci i seguenti dati al suo interno.

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

Per eseguire questa pagina, aggiungi il seguente percorso alla tua app.

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

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

Riceverai l'output come -

Quello che fa Pug è che converte questo markup dall'aspetto molto semplice in html. Non abbiamo bisogno di tenere traccia della chiusura dei nostri tag, non è necessario utilizzare le parole chiave class e id, piuttosto utilizzare "." e "#" per definirli. Il codice sopra viene prima convertito in

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

Pug è in grado di fare molto di più che semplificare il markup HTML. Esploriamo alcune di queste caratteristiche di Pug.

Tag semplici

I tag sono nidificati in base al loro rientro. Come nell'esempio sopra,<title> era rientrato all'interno di <head>tag, quindi era al suo interno. in ogni caso, il<body> tag era sulla stessa rientranza, quindi era un fratello di <head> etichetta.

Non è necessario chiudere i tag. Non appena Pug incontra il tag successivo sullo stesso livello o sul livello di rientro esterno, chiude il tag per noi.

Esistono tre metodi per inserire il testo all'interno di un tag:

  • Spazio separato -
h1 Welcome to Pug
  • Testo in pipe -
div
   | To insert multiline text, 
   | You can use the pipe operator.
  • Blocco di testo -
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.

Commenti

Pug utilizza la stessa sintassi di JavaScript (//) per la creazione di commenti. Questi commenti vengono convertiti in commenti html (<! - comment ->). Per esempio,

//This is a Pug comment

Questo commento viene convertito in -

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

Attributi

Per definire gli attributi, utilizziamo un elenco di attributi separati da virgole, tra parentesi. Gli attributi di classe e ID hanno rappresentazioni speciali. La seguente riga di codice copre la definizione di attributi, classi e id per un dato tag html.

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

Questa riga di codice viene convertita in -

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

Passaggio di valori ai modelli

Quando eseguiamo il rendering di un modello Pug, possiamo effettivamente passargli un valore dal nostro gestore di rotte, che possiamo quindi utilizzare nel nostro modello. Crea un nuovo gestore di route con il codice seguente.

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);

Quindi, crea un nuovo file di visualizzazione nella directory delle visualizzazioni, denominato dynamic.pug, utilizzando il codice seguente.

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

Aperto localhost:3000/dynamicnel tuo browser e il seguente dovrebbe essere l'output. -

Possiamo anche usare queste variabili passate all'interno del testo. Per inserire le variabili passate tra il testo di un tag, usiamo la sintassi # {variableName}. Ad esempio, nell'esempio sopra, se vogliamo inserire Greetings da TutorialsPoint, dobbiamo usare il seguente codice.

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

Questo metodo di utilizzo dei valori è chiamato interpolazione.

Condizionali

Possiamo usare anche istruzioni condizionali e costrutti di ciclo. Considera questo esempio pratico, se un utente è loggato vorremmo visualizzare "Ciao, Utente" e in caso contrario, allora vorremmo mostrargli un link "Accedi / Registrati". Per ottenere ciò, possiamo definire un semplice modello come:

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

Quando rendiamo questo usando le nostre rotte e se passiamo un oggetto come -

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

Darà un messaggio che mostra Ciao, Ayush. Tuttavia, se non passiamo alcun oggetto o ne passiamo uno senza chiave utente, otterremo un collegamento di registrazione.

Includi e componenti

Pug fornisce un modo molto intuitivo per creare componenti per una pagina web. Ad esempio, se vedi un sito di notizie, l'intestazione con logo e categorie è sempre fissa. Invece di copiarlo in ogni vista, possiamo usare un include. L'esempio seguente mostra come possiamo usare un include -

Crea tre visualizzazioni con il codice seguente:

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.

Crea un percorso per questo come segue.

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);

Vai a localhost:3000/components, dovresti ottenere il seguente output.

include può essere utilizzato anche per includere testo normale, CSS e JavaScript.

Ci sono molte altre funzionalità di Pug. Tuttavia, questi non rientrano nell'ambito di questo tutorial. Puoi esplorare ulteriormente Pug a Pug .

I moduli sono parte integrante del web. Quasi ogni sito web che visitiamo ci offre moduli che inviano o recuperano alcune informazioni per noi. Per iniziare con i moduli, installeremo prima il koa-body. Per installarlo, vai sul tuo terminale e usa -

$ npm install --save koa-body

Sostituisci il contenuto del file app.js con il codice seguente.

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);

Le nuove cose che stiamo facendo qui stanno importando il body parser e multer. Stiamo usando il body parser per analizzare le richieste di intestazione json e x-www-form-urlencoded, mentre usiamo multer per analizzare multipart / form-data.

Creiamo un modulo html per provarlo! Crea una nuova visualizzazione denominata form.pug con il codice seguente.

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

Esegui il tuo server usando -

nodemon index.js

Ora vai su localhost: 3000 / e compila il modulo come preferisci e invialo. Riceverai la risposta come:

Dai un'occhiata alla tua console, ti mostrerà il corpo della tua richiesta come oggetto JavaScript. Ad esempio:

Il this.request.bodyoggetto contiene il corpo della richiesta analizzata. Per utilizzare i campi di quell'oggetto, usali come normali oggetti JS.

Questo è solo un modo per inviare una richiesta. Ci sono molti altri modi, ma questi sono irrilevanti da trattare qui, perché la nostra app Koa gestirà tutte quelle richieste allo stesso modo. Per saperne di più sui diversi modi per effettuare una richiesta, dai un'occhiata a questa pagina.

Le applicazioni Web devono fornire la funzionalità per consentire il caricamento dei file. Vediamo come possiamo ricevere file dai client e archiviarli sul nostro server.

Abbiamo già utilizzato il middleware koa-body per l'analisi delle richieste. Questo middleware viene utilizzato anche per la gestione dei caricamenti di file. Creiamo un modulo che ci consenta di caricare file e quindi salvare questi file utilizzando Koa. Per prima cosa crea un modello denominatofile_upload.pug con i seguenti contenuti.

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")

Nota che devi dare lo stesso tipo di codifica come sopra nel tuo modulo. Ora gestiamo questi dati sul nostro server.

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);

Quando lo esegui, ottieni il seguente modulo.

Quando lo invii, la tua console produrrà il seguente output.

I file che sono stati caricati vengono memorizzati nel percorso nell'output precedente. È possibile accedere ai file nella richiesta utilizzandothis.request.body.files e i campi in tale richiesta di this.request.body.fields.

I file statici sono file che i client scaricano così come sono dal server. Crea una nuova directory,public. Express, per impostazione predefinita non ti consente di servire file statici.

Abbiamo bisogno di un middleware per servire a questo scopo. Vai avanti e installakoa-serve -

$ npm install --save koa-static

Ora dobbiamo usequesto middleware. Prima di allora crea una directory chiamata public. Memorizzeremo qui tutti i nostri file statici. Ciò ci consente di mantenere il codice del nostro server protetto poiché nulla al di sopra di questa cartella pubblica sarebbe accessibile ai client. Dopo aver creato una directory pubblica, crea un file denominatohello.txtin esso con qualsiasi contenuto che ti piace. Ora aggiungi quanto segue al tuo app.js.

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

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

app.listen(3000);

Note- Koa cerca i file relativi alla directory statica, quindi il nome della directory statica non fa parte dell'URL. La rotta di root è ora impostata sulla directory pubblica, quindi tutti i file statici caricati verranno considerati pubblici come root. Per verificare che funzioni correttamente, esegui la tua app e visitahttps://localhost:3000/hello.txt

Dovresti ottenere il seguente output. Nota che questo non è un documento HTML o una visualizzazione Pug, piuttosto è un semplice file txt.

Dir statiche multiple

Possiamo anche impostare più directory di risorse statiche utilizzando:

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

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

app.listen(3000);

Ora, quando richiediamo un file, Koa cercherà in queste directory e ci invierà il file corrispondente.

I cookie sono semplici file / dati di piccole dimensioni che vengono inviati al client con una richiesta del server e memorizzati sul lato client. Ogni volta che l'utente carica nuovamente il sito web, questo cookie viene inviato con la richiesta. Questo aiuta a tenere traccia delle azioni degli utenti. Esistono numerosi utilizzi dei cookie HTTP.

  • Gestione delle sessioni
  • Personalizzazione (sistemi di raccomandazione)
  • Tracciamento dell'utente

Per utilizzare i cookie con Koa, abbiamo le funzioni: ctx.cookies.set() e ctx.cookies.get(). Per impostare un nuovo cookie, definiamo un nuovo percorso nella nostra app 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);

Per verificare se il cookie è impostato o meno, vai sul tuo browser, avvia la console e inserisci -

console.log(document.cookie);

Questo produrrà il seguente output (potresti avere più cookie impostati forse a causa delle estensioni nel tuo browser).

"foo = bar"

Ecco un esempio di quanto sopra.

Il browser restituisce inoltre i cookie ogni volta che interroga il server. Per visualizzare un cookie sul tuo server, sulla console del server in una route, aggiungi il seguente codice a quella route.

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

La prossima volta che invierai una richiesta a questa route, otterrai il seguente output.

Cookies: foo = bar

Aggiunta di cookie con tempo di scadenza

Puoi aggiungere cookie che scadono. Per aggiungere un cookie che scade, è sufficiente passare un oggetto con la proprietà 'expires' impostata sull'ora in cui si desidera che scada. Per esempio,

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);

Eliminazione dei cookie esistenti

Per annullare l'impostazione di un cookie, è sufficiente impostare il cookie su una stringa vuota. Ad esempio, se è necessario cancellare un cookie denominatofoo, usa il codice seguente.

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);

Questo disattiverà il suddetto cookie. Nota che dovresti lasciare il fileHttpOnly opzione per essere vera quando non si utilizza il cookie nel codice lato client.

HTTP è senza stato, quindi per associare una richiesta a qualsiasi altra richiesta, è necessario un modo per memorizzare i dati dell'utente tra le richieste HTTP. I cookie e i parametri URL sono entrambi modi adatti per trasportare i dati tra il client e il server. Tuttavia, sono entrambi leggibili sul lato client. Le sessioni risolvono esattamente questo problema. Assegnate al cliente un ID e lui effettua tutte le ulteriori richieste utilizzando quell'ID. Le informazioni associate al client vengono memorizzate sul server collegato a questo ID.

Avremo bisogno della sessione koa, quindi installala usando -

npm install --save koa-session

Metteremo il file koa-sessionmiddleware in atto. In questo esempio, useremo la RAM per memorizzare le sessioni. Non utilizzarlo mai in ambienti di produzione. Il middleware della sessione gestisce tutto, ovvero la creazione della sessione, l'impostazione del cookie di sessione e la creazione dell'oggetto della sessione nell'oggetto contesto.

Ogni volta che facciamo di nuovo una richiesta dallo stesso client, avremo le informazioni sulla sua sessione memorizzate con noi (dato che il server non è stato riavviato). Possiamo aggiungere più proprietà a questo oggetto di sessione. Nell'esempio seguente, creeremo un contatore di visualizzazioni per un client.

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);

Ciò che fa il codice sopra è che, quando un utente visita il sito, crea una nuova sessione per l'utente e assegna un cookie. La prossima volta che l'utente visita, il cookie viene controllato e la variabile di sessione page_view viene aggiornata di conseguenza.

Ora se esegui l'app e vai a localhost:3000, otterrai la seguente risposta.

Se visiti nuovamente la pagina, il contatore delle pagine aumenterà. In questo caso, la pagina è stata aggiornata 12 volte.

L'autenticazione è un processo in cui le credenziali fornite vengono confrontate con quelle archiviate nel database delle informazioni degli utenti autorizzati su un sistema operativo locale o all'interno di un server di autenticazione. Se le credenziali corrispondono, il processo è completato e all'utente viene concessa l'autorizzazione per l'accesso.

Creeremo un sistema di autenticazione molto semplice che utilizzeremo Basic HTTP Authentication. Questo è il modo più semplice possibile per imporre il controllo degli accessi poiché non richiede cookie, sessioni o altro. Per usarlo, il client deve inviare l'intestazione di autorizzazione insieme a ogni richiesta che fa. Il nome utente e la password non sono crittografati, ma sono concatenati in una singola stringa come la seguente.

username:password

Questa stringa è codificata con Base64 e la parola Basic viene inserita prima di questo valore. Ad esempio, se il tuo nome utente è Ayush e la password India, la stringa"Ayush:India" verrebbe inviato come codificato nell'intestazione dell'autorizzazione.

Authorization: Basic QXl1c2g6SW5kaWE=

Per implementarlo nella tua app koa, avrai bisogno del middleware koa-basic-auth. Installalo usando -

$ npm install --save koa-basic-auth

Ora apri il tuo file app.js e inserisci il seguente codice al suo interno.

//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);

Abbiamo creato un middleware di gestione degli errori per gestire tutti gli errori relativi all'autenticazione. Quindi, abbiamo creato 2 percorsi:

  • /protected- È possibile accedere a questa route solo se l'utente invia l'intestazione di autenticazione corretta. Per tutti gli altri, darà un errore.

  • /unprotected - Questo percorso è accessibile da chiunque, con o senza l'autenticazione.

Ora se invii una richiesta a / protected senza un'intestazione di autenticazione o con le credenziali sbagliate, riceverai un errore. Per esempio,

$ curl https://localhost:3000/protected

Riceverai la risposta come:

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

Tuttavia, con le giuste credenziali, otterrai la risposta prevista. Per esempio,

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

Riceverai la risposta come:

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.

Il percorso / non protetto è ancora accessibile a tutti.

La compressione è un modo semplice ed efficace per risparmiare larghezza di banda e velocizzare il tuo sito. È compatibile solo con i browser moderni e dovrebbe essere utilizzato con cautela se gli utenti utilizzano anche browser legacy.

Quando si inviano risposte dal server, se viene utilizzata la compressione, può migliorare notevolmente il tempo di caricamento. Useremo un middleware chiamatokoa-compress per occuparsi della compressione dei file e impostare le intestazioni appropriate.

Vai avanti e installa il middleware usando -

$ npm install --save koa-compress

Ora nel tuo file app.js, aggiungi il seguente codice:

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);

Questo mette in atto il nostro middleware di compressione. L'opzione di filtro è una funzione che controlla il tipo di contenuto della risposta per decidere se comprimere. L'opzione di soglia è la dimensione minima della risposta in byte da comprimere. Ciò garantisce di non comprimere ogni piccola risposta.

Di seguito è una risposta senza compressione.

Di seguito è la risposta simile con la compressione.

Se guardi la scheda delle dimensioni in basso, puoi vedere molto bene la differenza tra i due. C'è un miglioramento di oltre il 150% quando comprimiamo i file.

La memorizzazione nella cache è il termine per memorizzare le risposte riutilizzabili al fine di rendere più veloci le richieste successive. Ogni browser viene fornito con un'implementazione di una cache HTTP. Tutto quello che dobbiamo fare è assicurarci che ogni risposta del server fornisca le direttive di intestazione HTTP corrette per indicare al browser quando e per quanto tempo la risposta può essere memorizzata nella cache dal browser.

Di seguito sono riportati alcuni vantaggi dell'inclusione della memorizzazione nella cache nelle app Web:

  • I costi della tua rete diminuiscono. Se i tuoi contenuti sono memorizzati nella cache, dovrai inviarne meno per ogni richiesta successiva.

  • La velocità e le prestazioni del tuo sito web aumentano.

  • I tuoi contenuti possono essere resi disponibili anche se il tuo client è offline.

Useremo il middleware koa-static-cache per implementare il caching nella nostra app. Installa questi middleware usando -

$ npm install --save koa-static-cache

Vai al tuo file app.js e aggiungi il codice seguente.

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);

Il koa-static-cacheil middleware viene utilizzato per memorizzare nella cache le risposte del server sul lato client. Ilcache-controlL'intestazione è impostata in base alle opzioni fornite durante l'inizializzazione dell'oggetto cache. Abbiamo impostato la scadenza di questa risposta memorizzata nella cache a 1 anno. Di seguito sono riportati i confronti delle richieste che abbiamo inviato prima e dopo che il file è stato memorizzato nella cache.

Prima che questo file venisse memorizzato nella cache, il codice di stato restituito era 200, che è OK. Le intestazioni della risposta avevano più informazioni relative al contenuto da memorizzare nella cache e avevano anche fornito un fileETag per il contenuto.

La volta successiva che è stata inviata la richiesta, è stata inviata insieme all'ETtag. Poiché il nostro contenuto non era cambiato sul server, anche il suo ETag corrispondente è rimasto lo stesso e al cliente è stato detto che la copia che ha localmente è aggiornata con ciò che il server avrebbe fornito e dovrebbe usare quella locale invece di richiedere ancora.

Note- Per invalidare un file memorizzato nella cache, è sufficiente modificarne il nome e aggiornarne il riferimento. Ciò assicurerà di avere un nuovo file da inviare al client e il client non potrà caricarlo di nuovo dalla cache.

Stiamo ricevendo le richieste, ma non le stiamo archiviando da nessuna parte. Abbiamo bisogno di un database per memorizzare i dati. Useremo un famoso database NoSQL chiamatoMongoDB. Per installare e leggere informazioni su Mongo, vai a questo link.

Per poter utilizzare Mongo con Koa, abbiamo bisogno di un'API client per il nodo. Ci sono più opzioni per noi, tuttavia per questo tutorial ci atteneremo alla mangusta . La mangusta è usata perdocument modelingin Node for MongoDB. La modellazione del documento significa che creeremo un fileModel (molto simile a un file class nella programmazione document-oriented), e poi produrremo documents utilizzando questo modello (come creiamo documents of a classin OOP). Tutta la nostra elaborazione verrà eseguita su questi "documenti", quindi, infine, scriveremo questi documenti nel nostro database.

Impostazione della mangusta

Ora che abbiamo installato Mongo, installiamo mongoose, nello stesso modo in cui abbiamo installato gli altri nostri pacchetti di nodi.

$ npm install --save mongoose

Prima di iniziare a usare mongoose, dobbiamo creare un database usando la shell Mongo. Per creare un nuovo database, apri il tuo terminale e inserisci "mongo". Verrà avviata una shell Mongo, immettere quanto segue.

use my_db

Verrà creato un nuovo database per te. Ogni volta che apri la shell Mongo, per impostazione predefinita "test" db e dovrai passare al tuo database usando lo stesso comando di cui sopra.

Per usare mongoose, lo richiederemo nel nostro file app.js e poi ci collegheremo al servizio mongod in esecuzione su 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);

Ora la nostra app è collegata al nostro database, creiamo un nuovo modello. Questo modello fungerà da raccolta nel nostro database. Per creare un nuovo modello, utilizzare il codice seguente, prima di definire qualsiasi percorso.

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);

Il codice precedente definisce lo schema per una persona e viene utilizzato per creare un modello di mangusta Person.

Salvataggio di documenti

Ora creeremo un nuovo modulo html, che otterrà i dettagli di una persona e lo salverà nel nostro database. Per creare il modulo, crea un nuovo file di visualizzazione chiamato person.pug nella directory delle visualizzazioni con il seguente contenuto.

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

Aggiungi anche un nuovo percorso get in index.js per eseguire il rendering di questo 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);

Vai a localhost: 3000 / persona per verificare se il nostro modulo viene visualizzato correttamente. Nota che questa è solo l'interfaccia utente, non funziona ancora. Ecco come appare la nostra forma.

Definiremo ora un gestore di post route in "/ person" che gestirà questa richiesta.

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);

Nel codice sopra, se riceviamo un campo vuoto o non riceviamo alcun campo, invieremo una risposta di errore. Tuttavia, se riceviamo un documento ben formato, creiamo un documento newPerson dal modello Person e lo salviamo nel nostro DB utilizzandonewPerson.save()funzione. Questo è definito in mongoose e accetta un callback come argomento. Questo callback ha due argomenti,error e response. Questo renderà la vista show_message, quindi dobbiamo creare anche quella.

Per mostrare la risposta da questo percorso, dovremo anche creare un file show_messageVisualizza. Crea una nuova vista con il codice seguente.

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!

Di seguito è riportata la risposta che riceviamo dopo aver inviato correttamente il modulo (show_message.pug).

Ora abbiamo un'interfaccia per creare persone!

Recupero di documenti

Mongoose fornisce molte funzioni per il recupero dei documenti, ci concentreremo su tre di queste. Tutte queste funzioni accettano anche un callback come ultimo parametro e, proprio come la funzione di salvataggio, i loro argomenti sono errore e risposta.

Le tre funzioni sono:

Model.find (condizioni, richiamata)

Questa funzione trova tutti i documenti che corrispondono ai campi nell'oggetto condizioni. Gli stessi operatori usati in Mongo funzionano anche con la mangusta. Ad esempio, questo recupererà tutti i documenti dalla raccolta delle persone.

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

Questo recupererà tutti i documenti in cui il nome del campo è "Ayush" e l'età è 20.

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

Possiamo anche fornire la proiezione di cui abbiamo bisogno, cioè i campi di cui abbiamo bisogno. Ad esempio, se vogliamo solo il filenames delle persone di cui nationalityè "indiano" , usiamo -

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

Model.findOne (condizioni, richiamata)

Questa funzione recupera sempre un unico documento più rilevante. Ha gli stessi argomenti esatti di Model.find ().

Model.findById (id, callback)

Questa funzione accetta l'estensione _id(definito da mongo) come primo argomento, una stringa di proiezione opzionale e un callback per gestire la risposta. Per esempio,

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

Creiamo un percorso per visualizzare tutti i record delle persone.

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);

Aggiornamento dei documenti

Mongoose fornisce tre funzioni per aggiornare i documenti.

Model.update (condizione, aggiornamenti, richiamata)

Questa funzione accetta una condizione e aggiorna l'oggetto come input e applica le modifiche a tutti i documenti che corrispondono alle condizioni nella raccolta. Ad esempio, il codice seguente aggiornerà tutti i documenti Person per avere una nazionalità "americana".

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

Model.findOneAndUpdate (condizione, aggiornamenti, richiamata)

Fa esattamente quello che dice. Trova un documento in base alla query e lo aggiorna in base al secondo argomento. Accetta anche una richiamata come ultimo argomento. Per esempio,

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

Model.findByIdAndUpdate (id, aggiornamenti, callback)

Questa funzione aggiorna un singolo documento identificato dal suo id. Per esempio,

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

Creiamo un percorso per aggiornare le persone. Questa sarà una rotta PUT con l'id come parametro e dettagli nel payload.

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);

Per testare questo percorso, inserisci quanto segue nel tuo terminale (sostituisci l'id con un id dalle persone create).

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

Questo aggiornerà il documento associato all'id fornito nel percorso con i dettagli di cui sopra.

Eliminazione di documenti

Abbiamo coperto Create, Read e Update, ora vedremo come utilizzare mangusta per eliminare i documenti. Ci sono tre funzioni qui, esattamente come l'aggiornamento.

Model.remove (condition, [callback])

Questa funzione accetta un oggetto condizione come input e rimuove tutti i documenti che soddisfano le condizioni. Ad esempio, se dobbiamo rimuovere tutte le persone di 20 anni,

Person.remove({age:20});

Model.findOneAndRemove (condizione, [callback])

Questa funzione rimuove un file single, documento più rilevante in base alle condizioni oggetto. Per esempio,

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

Model.findByIdAndRemove (id, [callback])

Questa funzione rimuove un singolo documento identificato dal suo id. Per esempio,

Person.findByIdAndRemove("507f1f77bcf86cd799439011");

Ora creiamo un percorso per eliminare le persone dal nostro database.

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);

Per testarlo, usa il seguente comando curl:

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

Questo rimuoverà la persona con l'id dato che produce il seguente messaggio. -

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

Questo spiega come possiamo creare semplici applicazioni CRUD usando MongoDB, mangusta e Koa. Per esplorare ulteriormente la mangusta, leggi i documenti dell'API.

Per creare applicazioni mobili, applicazioni a pagina singola, utilizzare chiamate AJAX e fornire dati ai client, avrai bisogno di un'API. Viene chiamato uno stile architettonico popolare su come strutturare e denominare queste API e gli endpointREST(Representational Transfer State). HTTP 1.1 è stato progettato tenendo presenti i principi REST. REST è stato introdotto daRoy Fielding nel 2000 nel suo articolo Fielding Dissertations.

Gli URI e i metodi RESTful ci forniscono quasi tutte le informazioni necessarie per elaborare una richiesta. La tabella seguente riassume come dovrebbero essere usati i vari verbi e come dovrebbero essere denominati gli URI. Verso la fine creeremo un'API per i film, quindi discutiamo di come sarà strutturata.

Metodo URI Dettagli Funzione
OTTENERE /film Sicuro, rimovibile Ottiene l'elenco di tutti i film e i relativi dettagli
OTTENERE / movies / 1234 Sicuro, rimovibile Ottiene i dettagli dell'id del film 1234
INVIARE /film N / A Crea un nuovo film con i dettagli forniti. La risposta contiene l'URI per questa risorsa appena creata.
METTERE / movies / 1234 Idempotente Modifica l'ID del film 1234 (ne crea uno se non esiste già). La risposta contiene l'URI per questa risorsa appena creata.
ELIMINA / movies / 1234 Idempotente L'ID film 1234 dovrebbe essere eliminato, se esistente. La risposta dovrebbe contenere lo stato della richiesta.
CANCELLA o Metti /film Non valido Non dovrebbe essere valido. DELETE e PUT dovrebbero specificare su quale risorsa stanno lavorando.

Ora creiamo questa API in Koa. Utilizzeremo JSON come formato dei dati di trasporto poiché è facile da lavorare in JavaScript e offre molti altri vantaggi. Sostituisci il tuo file index.js con il seguente -

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);

Ora che abbiamo configurato la nostra applicazione, concentriamoci sulla creazione dell'API. Per prima cosa imposta il file movies.js. Non stiamo utilizzando un database per archiviare i film ma li stiamo archiviando in memoria, quindi ogni volta che il server si riavvia i film da noi aggiunti svaniranno. Questo può essere facilmente imitato usando un database o un file (usando il modulo node fs).

Importa koa-router, crea un Router ed esportalo 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;

OTTIENI Percorsi

Definisci il percorso GET per ottenere tutti i film.

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

Questo è tutto. Per verificare se funziona correttamente, esegui l'app, quindi apri il terminale e inserisci -

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

Riceverai la seguente risposta:

[{"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}]

Abbiamo un percorso per ottenere tutti i film. Ora creiamo un percorso per ottenere un film specifico dal suo 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;
}

Questo ci darà i film in base all'ID che forniamo. Per provarlo, usa il seguente comando nel tuo terminale.

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

Riceverai la risposta come:

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

Se visiti un percorso non valido, produrrà un errore non GET, mentre se visiti un percorso valido con un ID che non esiste, produrrà un errore 404.

Abbiamo finito con le rotte GET. Ora, passiamo al percorso POST.

POST Route

Utilizzare il percorso seguente per gestire i dati POST.

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;
}

Questo creerà un nuovo film e lo memorizzerà nella variabile movies. Per testare questo percorso, inserisci quanto segue nel tuo terminale:

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

Riceverai la seguente risposta:

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

Per verificare se questo è stato aggiunto all'oggetto movies, eseguire nuovamente la richiesta get per / movies / 105. Riceverai la seguente risposta:

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

Passiamo alla creazione delle rotte PUT e DELETE.

PUT Route

Il percorso PUT è quasi esattamente lo stesso del percorso POST. Specificheremo l'ID per l'oggetto che verrà aggiornato / creato. Crea il percorso nel modo seguente:

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};
      }
   }
}

Questo percorso eseguirà la funzione specificata nella tabella sopra. Se esiste, aggiornerà l'oggetto con nuovi dettagli. Se non esiste, creerà un nuovo oggetto. Per provare questo percorso, usa il seguente comando curl. Questo aggiornerà un film esistente. Per creare un nuovo film, cambia semplicemente l'ID in un ID non esistente.

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

Risposta

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

ELIMINA percorso

Usa il codice seguente per creare un percorso di eliminazione.

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."};
   }
}

Prova il percorso nello stesso modo in cui abbiamo fatto per gli altri. In caso di eliminazione riuscita (ad esempio ID 105), otterrai:

{message: "Movie id 105 removed."}

Infine, il nostro file movies.js ha il seguente aspetto:

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;

Questo completa la nostra API REST. Ora puoi creare applicazioni molto più complesse usando questo semplice stile architettonico e Koa.

La registrazione è molto utile quando si creano applicazioni web in quanto ci dicono dove esattamente le cose sono andate storte. Otteniamo anche il contesto per le cose che sono andate storte e possiamo trovare possibili soluzioni per lo stesso.

Per abilitare il login in Koa, abbiamo bisogno del middleware, koa-logger. Installalo utilizzando il seguente comando.

$ npm install --save-dev koa-logger

Ora nella tua applicazione, aggiungi il codice seguente per abilitare la registrazione.

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)

Esegui questo server e visita qualsiasi percorso sul server. Dovresti vedere i registri come -

Ora, se ricevi un errore su un percorso o una richiesta specifica, questi log dovrebbero aiutarti a capire cosa è andato storto in ciascuno di essi.

Le impalcature ci consentono di creare facilmente un file skeleton for a web application. Abbiamo creato manualmente la nostra directory pubblica, aggiunto middleware, creato file di route separati, ecc. Uno strumento di scaffolding imposta tutte queste cose per noi in modo che possiamo iniziare direttamente a costruire la nostra applicazione.

Lo scaffolder che useremo si chiama Yeoman. È uno strumento di scaffolding creato per Node.js ma ha anche generatori per molti altri framework (come flask, rails, django, ecc.). Per installare yeoman, inserisci il seguente comando nel tuo terminale.

$ npm install -g yeoman

Yeoman utilizza i generatori per impalcare le applicazioni. Per controllare i generatori disponibili su npm da usare con yeoman, vai qui . Ai fini di questo tutorial, useremo il "generatore-koa". Per installare questo generatore, inserisci il seguente comando nel tuo terminale.

$ npm install -g generator-koa

Per utilizzare questo generatore, inserisci -

yo koa

Quindi creerà una struttura di directory e creerà i seguenti file per te. Installerà anche i moduli npm ei componenti bower necessari per te.

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.

Questo generatore crea per noi una struttura molto semplice.

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

Esplora i numerosi generatori disponibili per Koa e scegli quello che fa per te. I passaggi per lavorare con tutti i generatori sono gli stessi. Dovrai installare un generatore, eseguirlo usando yeoman, ti farà alcune domande e quindi creerà uno scheletro per la tua applicazione in base alle tue risposte.

Di seguito è riportato un elenco di risorse che abbiamo utilizzato durante lo sviluppo di questo tutorial:

  • Koajs.com

  • Koajs - Esempi Un elenco di esempi creati dalla comunità

  • Elenco dei middleware ufficiali e del terzo partito.

  • Un'API CRUD che utilizza koa.js - Un breve screencast che passa attraverso la creazione di un'API CRUD in Koa.js

  • Koa.js Quickstart screencast

  • Introduzione a Koa.js e ai generatori