Introduzione a Generators & Koa.js Parte 2

Cosa starai creando

Benvenuti alla seconda parte della nostra serie su generatori e Koa. Se ti sei perso puoi leggere la parte 1 qui. Prima di iniziare con il processo di sviluppo, assicurati di aver installato Node.js 0.11.9 o successivo.

In questa parte, creeremo un'API del dizionario utilizzando Koa.js e impareremo a conoscere il routing, la compressione, la registrazione, la limitazione della velocità e la gestione degli errori in Koa.js. Useremo anche Mongo come nostro archivio dati e impareremo brevemente sull'importazione dei dati in Mongo e sulla facilità con cui si esegue l'interrogazione in Koa. Infine, esamineremo il debug delle app di Koa.

Capire Koa

Koa ha cambiamenti radicali costruiti sotto il suo cofano che sfruttano la bontà del generatore di ES6. Oltre al cambiamento nel flusso di controllo, Koa introduce i propri oggetti personalizzati, come ad esempio Questo, questa richiesta, e this.response, che agiscono convenientemente come uno strato sintattico di zucchero costruito sopra gli oggetti req e res di Node, dando accesso a vari metodi di convenienza e getter / setter. 

Oltre alla convenienza, Koa ripulisce anche il middleware che, in Express, faceva affidamento su brutti hack che spesso modificavano gli oggetti core. Fornisce inoltre una migliore gestione del flusso.

Aspetta, cosa è un middleware?

Un middleware è una funzione collegabile che aggiunge o rimuove una particolare funzionalità eseguendo un po 'di lavoro negli oggetti richiesta / risposta in Node.js.

Koa's Middleware

Un middleware Koa è essenzialmente una funzione generatore che restituisce una funzione generatore e ne accetta un'altra. Di solito, un'applicazione ha una serie di middleware che vengono eseguiti per ogni richiesta. 

Inoltre, un middleware deve cedere al prossimo middleware 'downstream' se è eseguito da un 'middleware upstream'. Ne discuteremo di più nella sezione relativa alla gestione degli errori.

Costruire il middleware

Solo un'ultima cosa: per aggiungere un middleware alla tua applicazione Koa, usiamo il koa.use () metodo e fornire la funzione middleware come argomento. Esempio: app.use (KOA-logger) aggiunge koa-logger all'elenco di middleware utilizzato dalla nostra applicazione.

Costruire l'applicazione

Per iniziare con l'API del dizionario, abbiamo bisogno di un set di definizioni funzionante. Per ricreare questo scenario di vita reale, abbiamo deciso di andare con un set di dati reale. Abbiamo preso il dump della definizione da Wikipedia e l'abbiamo caricato in Mongo. Il set consisteva in circa 700.000 parole mentre importavamo solo la discarica inglese. Ogni record (o documento) consiste di una parola, il suo tipo e il suo significato. Puoi leggere ulteriori informazioni sul processo di importazione in import.txt file nel repository.

Per spostarti lungo il processo di sviluppo, clona il repository e controlla i tuoi progressi passando a diversi commit. Per clonare il repository, utilizzare il seguente comando:

$ git clone https://github.com/bhanuc/dictapi.git

Possiamo iniziare creando un server di base Koa:

var koa = require ('koa'); var app = koa (); app.use (funzione * (successiva) this.type = 'json'; this.status = 200; this.body = 'Welcome': 'Questa è un'applicazione di livello 2 Hello World !!';); if (! module.parent) app.listen (3000); console.log ('Hello World è in esecuzione su http: // localhost: 3000 /'); 

Nella prima riga, importiamo Koa e salviamo un'istanza nella variabile app. Quindi aggiungiamo un singolo middleware nella riga 5, che è una funzione di generatore anonimo che prende come parametro la variabile successiva. Qui, impostiamo il tipo e il codice di stato della risposta, che viene anche determinato automaticamente, ma possiamo anche impostarli manualmente. Quindi finalmente impostiamo il corpo della risposta. 

Dal momento che abbiamo impostato il corpo nel nostro primo middleware, questo segnerà la fine di ogni ciclo di richieste e nessun altro middleware sarà coinvolto. Infine, iniziamo il server chiamando il suo ascolta metodo e passare il numero di porta come parametro.

Possiamo avviare il server eseguendo lo script tramite:

$ npm install koa $ node --harmony index.js

Puoi raggiungere direttamente questa fase spostandoti sul commit 6858ae0:

$ git checkout 6858ae0

Aggiunta di funzionalità di routing

Il routing ci consente di reindirizzare richieste diverse a diverse funzioni sulla base del tipo di richiesta e dell'URL. Ad esempio, potremmo voler rispondere /accesso diversamente da Iscriviti. Questo può essere fatto aggiungendo un middleware, che controlla manualmente l'URL della richiesta ricevuta ed esegue le funzioni corrispondenti. Oppure, invece di scrivere manualmente quel middleware, possiamo usare un middleware di comunità, noto anche come modulo middleware.

Per aggiungere funzionalità di routing alla nostra applicazione, useremo un modulo di comunità chiamato koa-router

Usare koa-router, modificheremo il codice esistente nel codice mostrato di seguito:

var koa = require ('koa'); var app = koa (); var router = require ('koa-router'); var mount = require ('koa-mount'); var handler = function * (next) this.type = 'json'; this.status = 200; this.body = 'Welcome': 'Questa è un'applicazione di livello 2 Hello World !!'; ; var APIv1 = new router (); APIv1.get ('/ all', gestore); app.use (mount ('/ v1', APIv1.middleware ())); if (! module.parent) app.listen (3000); console.log ('Hello World è in esecuzione su http: // localhost: 3000 /'); 

Qui abbiamo importato due moduli, dove router I negozi koa-router e montare memorizza il koa-mount modulo, permettendoci di utilizzare il router nella nostra applicazione Koa.

Sulla linea 6, abbiamo definito il nostro gestore funzione, che è la stessa funzione di prima, ma qui abbiamo dato un nome. Alla riga 12, salviamo un'istanza del router APIv1, e sulla linea 13 registriamo il nostro gestore per tutto il OTTENERE richieste sul percorso /tutti

Quindi tutte le richieste tranne quando viene inviata una richiesta di ottenere localhost: 3000 / all restituirà "non trovato". Finalmente sulla linea 15, usiamo montare middleware, che fornisce una funzione generatore utilizzabile che può essere alimentata app.use ().

Per raggiungere direttamente questo passaggio o confrontare la tua applicazione, esegui il seguente comando nel repository clonato:

$ git checkout 8f0d4e8

Prima di eseguire la nostra applicazione, ora dobbiamo installare koa-router e koa-mount utilizzando npm. Osserviamo che con l'aumentare della complessità della nostra applicazione, aumenta anche il numero di moduli / dipendenze. 

Per tenere traccia di tutte le informazioni relative al progetto e rendere disponibili i dati npm, memorizziamo tutte le informazioni in package.json comprese tutte le dipendenze. È possibile creare manualmente package.json o utilizzando un'interfaccia della riga di comando interattiva che viene aperta utilizzando $ npm init comando.

"name": "koa-api-dictionary", "version": "0.0.1", "description": "applicazione koa-api-dictionary", "main": "index", "author": " nome ":" Bhanu Pratap Chaudhary "," email ":" [email protected] "," repository ": " tipo ":" git "," url ":" https://github.com/bhanuc/ dictapi.git "," license ":" MIT "," engines ": " node ":"> = 0.11.13 " 

Un minimo package.json il file è simile a quello sopra. 

Una volta package.json è presente, puoi salvare la dipendenza usando il seguente comando:

$ npm install  --salvare

Ad esempio: In questo caso, installeremo i moduli utilizzando il seguente comando per salvare le dipendenze in package.json.

$ npm installa koa-router koa-mount --save

Ora puoi eseguire l'applicazione usando $ node --harmony index.js

Puoi leggere di più su package.json Qui.

Aggiunta di route per l'API del dizionario

Inizieremo creando due percorsi per l'API, uno per ottenere un singolo risultato in una query più veloce e un secondo per ottenere tutte le parole corrispondenti (che è più lento per la prima volta). 

Per mantenere le cose gestibili, manterremo tutte le funzioni API in una cartella separata chiamata api e un file chiamato api.js, e importarlo più tardi nel nostro principale index.js file.

var monk = require ('monk'); var wrap = require ('co-monk'); var db = monk ('localhost / mydb'); var words = wrap (db.get ('words')); / ** * Ottieni tutti i risultati. * / exports.all = function * () if (this.request.query.word) var res = yield words.find (word: this.request.query.word); this.body = res;  else this.response.status = 404; ; / ** * OTTIENI un singolo risultato. * / exports.single = function * () if (this.request.query.word) var res = yield words.findOne (word: this.request.query.word); this.body = res;  else this.response.status = 404; ;

Qui stiamo usando co-monaco, che funge da involucro monaco, rendendo molto facile per noi interrogare MongoDB usando i generatori in Koa. Qui, importiamo monaco e co-monaco, e connettersi all'istanza MongoDB sulla linea 3. Chiamiamo avvolgere () sulle raccolte, per renderle compatibili con il generatore. 

Quindi aggiungiamo due metodi di generatore chiamati tutti e singolo come una proprietà del esportazioni variabile in modo che possano essere importati in altri file. In ognuna delle funzioni, prima controlliamo il parametro di query 'word'. Se presente, chiediamo il risultato oppure rispondiamo con un errore 404. 

Noi usiamo il dare la precedenza parola chiave per attendere i risultati come discusso nel primo articolo, che sospende l'esecuzione fino al ricevimento del risultato. Sulla linea 12, usiamo il trova metodo, che restituisce tutte le parole corrispondenti, memorizzate in res e successivamente rimandate. Sulla linea 23, usiamo il trova uno metodo disponibile sulla collezione, che restituisce il primo risultato corrispondente. 

Assegnazione di questi gestori alle rotte

var koa = require ('koa'); var app = koa (); var router = require ('koa-router'); var mount = require ('koa-mount'); var api = require ('./ api / api.js'); var APIv1 = new router (); APIv1.get ('/ all', api.all); APIv1.get ('/ single', api.single); app.use (mount ('/ v1', APIv1.middleware ())); if (! module.parent) app.listen (3000); console.log ('Dictapi è in esecuzione su http: // localhost: 3000 /');

Qui importiamo i metodi esportati da api.js e assegniamo i gestori a OTTENERE itinerari /tutti  / singolo e abbiamo un'API pienamente funzionale e un'applicazione pronta.

Per eseguire l'applicazione, è sufficiente installare il monaco e co-monaco moduli usando il comando qui sotto. Inoltre, assicurati di avere un'istanza in esecuzione di MongoDB in cui hai importato la raccolta presente nel repository git usando le istruzioni menzionate in import.txtweird.

$ npm installa monk in co-monk --save

Ora puoi eseguire l'applicazione usando il seguente comando:

$ node --harmony index.js

È possibile aprire il browser e aprire i seguenti URL per verificare il funzionamento dell'applicazione. Sostituisci 'nuovo' con la parola che vuoi interrogare.

  • http: // localhost: 3000 / v1 / all parola = new
  • http: // localhost: 3000 / v1 / sola parola = new

Per raggiungere direttamente questo passaggio o confrontare la tua applicazione, esegui il seguente comando nel repository clonato:

$ git checkout f1076eb 

Gestione degli errori in Koa

Utilizzando i middleware a cascata, possiamo rilevare gli errori usando il prova a prendere meccanismo, poiché ogni middleware può rispondere mentre cede a valle e a monte. Quindi, se aggiungiamo un Prova e cattura middleware all'inizio dell'applicazione, catturerà tutti gli errori incontrati dalla richiesta nel resto del middleware in quanto sarà l'ultimo middleware durante l'upstreaming. Aggiunta del seguente codice alla riga 10 o precedente in index.js dovrebbe funzionare.

app.use (function * (next) try yield next; // passa l'esecuzione ai middlewares downstream catch (err) // eseguito solo quando si verifica un errore e nessun altro middleware risponde alla richiesta this.type = 'json'; // facoltativo qui this.status = err.status || 500; this.body = 'error': 'L'applicazione è semplicemente andata in pezzi, si spera che la NSA abbia tutti i log;)'; // delegare l'errore all'applicazione this.app.emit ('error', err, this); );

Aggiunta di registrazione e limitazione della velocità all'applicazione

La memorizzazione dei registri è una parte essenziale di un'applicazione moderna, poiché i registri sono molto utili per il debug e la ricerca di problemi in un'applicazione. Inoltre memorizzano tutte le attività e quindi possono essere utilizzate per scoprire i modelli di attività degli utenti e altri interessanti modelli. 

La limitazione della velocità è diventata anche una parte essenziale delle applicazioni di oggi, dove è importante impedire agli spammer e ai robot di sprecare le preziose risorse del server e impedire loro di raschiare la tua API.

È abbastanza facile aggiungere la registrazione e la limitazione della velocità alla nostra applicazione Koa. Utilizzeremo due moduli comunitari: koa-logger e koa-meglio-rate-limiting. Abbiamo bisogno di aggiungere il seguente codice alla nostra applicazione:

var logger = require ('koa-logger'); var limit = require ('koa-better-ratelimit'); // Aggiungi le linee sotto il middleware degli errori. app.use (limite (durata: 1000 * 60 * 3, // 3 min max: 10, lista nera: [])); app.use (logger ());

Qui abbiamo importato due moduli e li abbiamo aggiunti come middleware. Il registratore registrerà ogni richiesta e stamperà nel stdout del processo che può essere facilmente salvato in un file. E il limite del middleware limita il numero di richieste che un determinato utente può richiedere in un determinato intervallo di tempo (qui sono richieste al massimo dieci in tre minuti). Inoltre è possibile aggiungere una serie di indirizzi IP che verranno inseriti nella lista nera e la loro richiesta non verrà elaborata.

Ricordarsi di installare i moduli prima di utilizzare il codice utilizzando: 

$ npm installa koa-logger koa-better-ratelimit --save

Comprimere il traffico

Uno dei modi per garantire una consegna più rapida è gzip la tua risposta, che è abbastanza semplice in Koa. Per comprimere il tuo traffico in Koa, puoi usare il koa-compress modulo. 

Qui, le opzioni possono essere un oggetto vuoto o possono essere configurate secondo il requisito.

var compress = require ('koa-compress'); var opts = filter: function (content_type) return /text/i.test(content_type), // filtra le richieste da comprimere usando la regex threshold: 2048, // dimensione minima per comprimere flush: require ('zlib') .Z_SYNC_FLUSH;  // usa il codice qui sotto per aggiungere il middleware all'applicazione app.use (comprimere (opts)); 

Puoi persino disattivare la compressione in una richiesta aggiungendo il seguente codice a un middleware:

this.compress = true;

Non dimenticare di installare compress usando npm

$ npm install compress --save 

Per raggiungere direttamente questo passaggio o confrontare la tua applicazione, esegui il seguente comando nel repository clonato:

git checkout 8f5b5a6 

Test di scrittura

Il test dovrebbe essere una parte essenziale di tutto il codice e uno dovrebbe mirare alla massima copertura del test. In questo articolo, scriveremo test per i percorsi accessibili dalla nostra applicazione. Useremo supertest e Mocha per creare i nostri test. 

Memorizzeremo il nostro test in test.js nel api cartella. In entrambi i test, prima descriviamo il nostro test, dandogli un nome più leggibile. Successivamente, passeremo una funzione anonima che descrive il comportamento corretto del test e prende una callback che contiene il test effettivo. In ogni test, importiamo la nostra applicazione, iniziamo il server, descriviamo il tipo di richiesta, l'URL e la query, quindi impostiamo la codifica su gzip. Alla fine controlliamo la risposta se è corretta.

var request = require ('supertest'); var api = require ('... /index.js'); define ('GET all', function () it ('dovrebbe rispondere con tutte le parole', function (done) var app = api; request (app.listen ()) .get ('/ v1 / all') .query (word: 'new') .set ('Accept-Encoding', 'gzip') .expect ('Content-Type', / json /) .expect (200) .end (done);) ) descrive ('GET / v1 / single', function () it ('dovrebbe rispondere con un singolo risultato', function (done) var app = api; request (app.listen ()) .get ('/ v1 / single ') .query (word:' new ') .set (' Accept-Encoding ',' gzip ') .expect (200) .expect (' Content-Type ', / json /) .end ( function (err, res) if (err) gira err; else if (! ('_ id' in res.body)) restituisce "id mancante"; if (! ('word' in res.body)) lancia nuovo Errore ("parola mancante"); done (););))

Per eseguire il nostro test, faremo un Makefile:

test: @ NODE_ENV = test ./node_modules/.bin/mocha \ --require dovrebbe \ --reporter nyan \ --harmony \ --bail \ api / test.js .PHONY: test

Qui, abbiamo configurato il reporter (nyan cat) e il framework di test (mocha). Si noti che l'importazione dovrebbe aggiungere --armonia per abilitare la modalità ES6. Infine, specifichiamo anche la posizione di tutti i test. UN Makefile può essere configurato per test infiniti della tua applicazione.

Ora per testare la tua app, basta usare il seguente comando nella directory principale dell'applicazione. 

$ fare un test

Ricorda solo di installare i moduli di test (mocha, dovrebbe, supertest) prima di testare, usando il comando seguente: 

$ npm install mocha dovrebbe mocha --save-dev 

In esecuzione in produzione

Per far funzionare le nostre applicazioni in produzione, useremo PM2, che è un utile monitor di processo Node. Dovremmo disabilitare l'app logger mentre è in produzione; può essere automatizzato usando variabili d'ambiente.

Per installare PM2, immettere il seguente comando nel terminale

$ npm installa pm2 -g 

E la nostra app può essere lanciata usando il seguente comando:

$ pm2 start index.js --node-args = "- harmony" 

Ora, anche se la nostra applicazione si arresta, si riavvierà automaticamente e potrai dormire sonni tranquilli. 

Conclusione

Koa è un middleware leggero ed espressivo per Node.js che rende più piacevole il processo di scrittura di applicazioni Web e API. 

Ti permette di sfruttare una moltitudine di moduli di comunità per estendere la funzionalità della tua applicazione e semplificare tutte le attività banali, rendendo lo sviluppo web un'attività divertente. 

Non esitare a lasciare commenti, domande o altre informazioni nel campo sottostante.