Inleiding tot generatoren en Koa.js deel 2

Wat je gaat creëren

Welkom bij het tweede deel van onze serie over generatoren en Koa. Als je het hebt gemist, kun je hier deel 1 lezen. Voordat u begint met het ontwikkelingsproces, moet u ervoor zorgen dat u Node.js 0.11.9 of hoger hebt geïnstalleerd.

In dit deel maken we een woordenboek-API met behulp van Koa.js en leert u meer over routering, compressie, logboekregistratie, snelheidsbeperking en foutafhandeling in Koa.js. We gebruiken Mongo ook als onze datastore en leren kort over het importeren van gegevens in Mongo en het gemak dat gepaard gaat met query's in Koa. Ten slotte zullen we kijken naar het debuggen van Koa-apps.

Koa begrijpen

Koa heeft onder zijn motorkap radicale veranderingen doorgevoerd die de generator-goedheid van ES6 gebruiken. Naast de verandering in de besturingsstroom introduceert Koa zijn eigen aangepaste objecten, zoals deze, dit verzoek, en this.response, die zich gemakkelijk gedragen als een syntactische-suikernaag bovenop de noden en res-objecten van Node, waardoor je toegang hebt tot verschillende gemaksmethoden en getters / setters. 

Naast gemak ruimt Koa ook de middleware op die in Express vertrouwt op lelijke hacks die vaak kernobjecten hebben aangepast. Het zorgt ook voor een betere afhandeling van de stream.

Wacht, wat is een middleware?

Een middleware is een insteekbare functie die een bepaald stuk functionaliteit toevoegt of verwijdert door wat werk te doen in de aanvraag / reactieobjecten in Node.js.

Koa's middleware

Een Koa-middleware is in wezen een generatorfunctie die één generatorfunctie retourneert en een andere accepteert. Gewoonlijk heeft een toepassing een reeks middleware die voor elk verzoek wordt uitgevoerd. 

Ook moet een middleware wijken voor de volgende 'stroomafwaartse' middleware als deze wordt uitgevoerd door een 'stroomopwaartse middleware'. We zullen hier meer over bespreken in de sectie over foutafhandeling.

Middleware bouwen

Nog een laatste ding: om een ​​middleware aan je Koa-applicatie toe te voegen, gebruiken we de koa.use () methode en lever de middleware-functie als het argument. Voorbeeld: app.use (koa-logger) voegt KOA-logger naar de lijst met middleware die onze applicatie gebruikt.

De applicatie bouwen

Om te beginnen met de woordenboek-API hebben we een werkende reeks definities nodig. Om dit real-life scenario opnieuw te creëren, hebben we besloten om te gaan met een echte dataset. We hebben de definitiedump van Wikipedia overgenomen en in Mongo geladen. De set bestond uit ongeveer 700.000 woorden omdat we alleen de Engelse dump importeerden. Elke record (of document) bestaat uit een woord, het type en de betekenis ervan. U kunt meer lezen over het importproces in de import.txt bestand in de repository.

Om door het ontwikkelingsproces te gaan, klopt u de repository en controleert u uw voortgang door over te schakelen naar verschillende commits. Gebruik de volgende opdracht om de repo te klonen:

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

We kunnen beginnen met het maken van een basisserver Koa:

var koa = require ('koa'); var app = koa (); app.use (function * (volgende) this.type = 'json'; this.status = 200; this.body = 'Welcome': 'Dit is een level 2 Hello World Application !!';); if (! module.parent) app.listen (3000); console.log ('Hello World wordt uitgevoerd op http: // localhost: 3000 /'); 

In de eerste regel importeren we Koa en slaan we een exemplaar op in de app-variabele. Vervolgens voegen we een enkele middleware toe in regel 5, wat een anonieme generatorfunctie is die de volgende variabele als parameter gebruikt. Hier stellen we het type en de statuscode van het antwoord in, die ook automatisch wordt bepaald, maar we kunnen deze ook handmatig instellen. Dan stellen we uiteindelijk de hoofdtekst van het antwoord in. 

Aangezien we de body in onze eerste middleware hebben geplaatst, zal dit het einde betekenen van elke request-cyclus en zal er geen andere middleware bij betrokken zijn. Ten slotte starten we de server door het te bellen luister methode en geef het poortnummer door als een parameter.

We kunnen de server starten door het script uit te voeren via:

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

Je kunt dit stadium direct bereiken door naar commit te gaan 6858ae0:

$ git afrekenen 6858ae0

Routingmogelijkheden toevoegen

Routering stelt ons in staat om verschillende verzoeken om te leiden naar verschillende functies op basis van aanvraagtype en URL. We willen bijvoorbeeld reageren op /Log in anders dan inschrijven. Dit kan worden gedaan door een middleware toe te voegen, die handmatig de URL van het ontvangen verzoek controleert en overeenkomstige functies uitvoert. Of, in plaats van het handmatig schrijven van die middleware, kunnen we een door de community gemaakte middleware gebruiken, ook bekend als een middleware-module.

Om routeringsmogelijkheden toe te voegen aan onze applicatie, gebruiken we een community-module met de naam KOA-router

Gebruiken KOA-router, we zullen de bestaande code aanpassen aan de onderstaande code:

var koa = require ('koa'); var app = koa (); var router = require ('koa-router'); var mount = require ('koa-mount'); var handler = function * (volgende) this.type = 'json'; this.status = 200; this.body = 'Welkom': 'Dit is een level 2 Hello World Application !!'; ; var APIv1 = nieuwe router (); APIv1.get ('/ all', handler); app.use (mount ('/ v1', APIv1.middleware ())); if (! module.parent) app.listen (3000); console.log ('Hello World wordt uitgevoerd op http: // localhost: 3000 /'); 

Hier hebben we twee modules geïmporteerd, waar router winkel KOA-router en berg slaat het op KOA-mount module, waardoor we de router kunnen gebruiken in onze Koa-applicatie.

Op regel 6 hebben we onze handler functie, wat dezelfde functie is als voorheen, maar hier hebben we het een naam gegeven. Op regel 12 slaan we een instantie van de router op APIv1, en op regel 13 registreren we onze handler voor alle KRIJGEN verzoeken op route /allemaal

Dus alle verzoeken behalve wanneer een verzoek wordt verzonden naar localhost: 3000 / all zal terugkeren "niet gevonden". Eindelijk op regel 15, gebruiken we berg middleware, die een bruikbare generatorfunctie geeft waarnaar kan worden gevoed app.use ().

Om deze stap direct te bereiken of uw toepassing te vergelijken, voert u de volgende opdracht uit in de gekloonde repo:

$ git checkout 8f0d4e8

Voordat we onze applicatie uitvoeren, moeten we nu installeren KOA-router en KOA-mount gebruik makend van NPM. We zien dat naarmate de complexiteit van onze applicatie toeneemt, het aantal modules / afhankelijkheden ook toeneemt. 

Om alle informatie over het project bij te houden en die gegevens beschikbaar te maken voor NPM, we slaan alle informatie op package.json inclusief alle afhankelijkheden. U kunt package.json handmatig maken of met behulp van een interactieve opdrachtregelinterface die wordt geopend met behulp van de $ npm init commando.

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

Een zeer minimaal package.json bestand lijkt op het bovenstaande. 

Een keer package.json aanwezig is, kunt u de afhankelijkheid opslaan met de volgende opdracht:

$ npm installatie  --opslaan

Bijvoorbeeld: in dit geval zullen we de modules installeren met behulp van de volgende opdracht om de afhankelijkheden op te slaan package.json.

$ npm install koa-router koa-mount - opslaan

Nu kunt u de toepassing uitvoeren met $ node --harmony index.js

U kunt meer lezen over package.json hier.

Routes voor de woordenboek-API toevoegen

We zullen beginnen met het maken van twee routes voor de API, een voor het krijgen van een enkel resultaat in een snellere query en een seconde om alle overeenkomende woorden te krijgen (wat voor het eerst langzamer is). 

Om de zaken beheersbaar te houden, houden we alle API-functies in een aparte map met de naam api en een bestand genaamd api.js, en importeer het later in onze hoofdtabel index.js het dossier.

var monk = require ('monk'); var wrap = require ('co-monk'); var db = monk ('localhost / mydb'); var words = wrap (db.get ('words')); / ** * KRIJG alle resultaten. * / exports.all = function * () if (this.request.query.word) var res = render words.find (word: this.request.query.word); this.body = res;  else this.response.status = 404; ; / ** * KRIJG een enkel resultaat. * / exports.single = function * () if (this.request.query.word) var res = render words.findOne (word: this.request.query.word); this.body = res;  else this.response.status = 404; ;

Hier gebruiken we co-monnik, die een verpakking omgeeft monnik, waardoor het voor ons heel gemakkelijk is om MongoDB te ondervragen met behulp van generatoren in Koa. Hier importeren we monnik en co-monnik, en maak verbinding met het MongoDB-exemplaar op regel 3. We bellen wikkelen() op collecties, om ze generatorvriendelijk te maken. 

Vervolgens voegen we twee genoemde generatormethoden toe allemaal en single als een eigendom van de export variabele zodat ze in andere bestanden kunnen worden geïmporteerd. In elk van de functies controleren we eerst de queryparameter 'woord'. Indien aanwezig, vragen we naar het resultaat, anders antwoorden we met een 404-fout. 

Wij gebruiken de opbrengst sleutelwoord om te wachten op de resultaten zoals besproken in het eerste artikel, dat de uitvoering pauzeert totdat het resultaat is ontvangen. Op regel 12 gebruiken we de vind methode, die alle overeenkomende woorden retourneert, die worden opgeslagen in res en vervolgens worden teruggestuurd. Op regel 23 gebruiken we de vind een methode beschikbaar in de verzameling, die het eerste overeenkomende resultaat retourneert. 

Deze handlers toewijzen aan routes

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 = nieuwe 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 wordt uitgevoerd op http: // localhost: 3000 /');

Hier importeren we geëxporteerde methoden van api.js en we wijzen handlers toe aan KRIJGEN routes /allemaal  / single en we hebben een volledig functionele API en applicatie klaar.

Om de applicatie uit te voeren, hoeft u alleen de monnik en co-monnik modules met behulp van de onderstaande opdracht. Zorg er ook voor dat je een lopend exemplaar van MongoDB hebt waarin je de verzameling die in de git-repository aanwezig is, hebt geïmporteerd met behulp van de instructies die worden genoemd in import.txtweird.

$ npm installeer monk co-monk - save

Nu kunt u de applicatie uitvoeren met behulp van de volgende opdracht:

$ node --harmony index.js

U kunt de browser openen en de volgende URL's openen om de werking van de toepassing te controleren. Vervang 'nieuw' door het woord dat u wilt opvragen.

  • http: // localhost: 3000 / v1 / all word = new
  • http: // localhost: 3000 / v1 / enkel woord = new

Om deze stap direct te bereiken of uw toepassing te vergelijken, voert u de volgende opdracht uit in de gekloonde repo:

$ git afrekenen f1076eb 

Foutafhandeling in Koa

Door trapsgewijze middlewares te gebruiken, kunnen we fouten opsporen met behulp van de proberen te vangen mechanisme, omdat elk middleware kan reageren terwijl het meegeeft zowel stroomafwaarts als stroomopwaarts. Dus als we een toevoegen Probeer en vang middleware in het begin van de applicatie, het zal alle fouten opvangen die door de aanvraag in de rest van de middleware worden aangetroffen, aangezien dit de laatste middleware is tijdens upstreaming. De volgende code toevoegen op regel 10 of eerder in index.js zou moeten werken.

app.use (function * (volgende) try yield next; // geef de uitvoering door aan downstream middlewares catch (err) // wordt alleen uitgevoerd wanneer er een fout optreedt en geen andere middleware reageert op het verzoek this.type = 'json'; // optioneel hier this.status = err.status || 500; this.body = 'error': 'De applicatie is gewoon gek geworden, hopelijk heeft NSA alle logs;)'; // delegeer de fout terug naar de toepassing this.app.emit ('error', eh, this); );

Logging en snelheidsbeperking toevoegen aan de applicatie

Het opslaan van logs is een essentieel onderdeel van een moderne applicatie, omdat logs zeer nuttig zijn bij het opsporen van fouten en het achterhalen van problemen in een toepassing. Ze slaan ook alle activiteiten op en kunnen dus worden gebruikt om gebruikersactiviteitspatronen en interessante andere patronen te achterhalen. 

Snelheidsbeperking is ook een essentieel onderdeel geworden van moderne toepassingen, waarbij het belangrijk is om te voorkomen dat spammers en bots uw kostbare serverbronnen verspillen en hen ervan weerhouden uw API te schrapen..

Het is vrij eenvoudig om logging en snelheidsbeperking toe te voegen aan onze Koa-applicatie. We zullen twee community-modules gebruiken: KOA-logger en KOA-beter-snelheidsbeperkende. We moeten de volgende code toevoegen aan onze applicatie:

var logger = require ('koa-logger'); var limit = require ('koa-better-ratelimit'); // Voeg de onderstaande regels toe net onder foutmiddleware. app.use (limit (duration: 1000 * 60 * 3, // 3 min max: 10, blacklist: [])); app.use (logger ());

Hier hebben we twee modules geïmporteerd en toegevoegd als middleware. De logger logt elke aanvraag en drukt in de stdout van het proces dat gemakkelijk in een bestand kan worden opgeslagen. Limiet voor middleware beperkt het aantal verzoeken dat een bepaalde gebruiker in een bepaalde periode kan aanvragen (hier zijn maximaal tien verzoeken binnen drie minuten). U kunt ook een reeks IP-adressen toevoegen die op de zwarte lijst worden geplaatst en hun verzoek niet zal worden verwerkt.

Vergeet niet om de modules te installeren voordat u de code gebruikt: 

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

Het comprimeren van het verkeer

Een van de manieren om een ​​snellere levering te garanderen, is door je reactie te gzippen, wat vrij eenvoudig is in Koa. Om uw verkeer in Koa te comprimeren, kunt u de koa comprimeren module. 

Hier kunnen opties een leeg object zijn of kunnen ze worden geconfigureerd volgens de vereisten.

var compres = require ('koa-compress'); var opts = filter: function (content_type) return /text/i.test(content_type), // filterverzoeken worden gecomprimeerd met behulp van regex-drempel: 2048, // minimumgrootte om flush te comprimeren: require ('zlib') .Z_SYNC_FLUSH;  // gebruik de onderstaande code om de middleware toe te voegen aan de applicatie app.use (comprimeren (opts)); 

U kunt compressie zelfs in een verzoek uitschakelen door de volgende code aan een middleware toe te voegen:

this.compress = true;

Vergeet niet om comprimeren met behulp van te installeren NPM

$ npm installeer comprimeren - opslaan 

Om deze stap direct te bereiken of uw toepassing te vergelijken, voert u de volgende opdracht uit in de gekloonde repo:

git uitchecken 8f5b5a6 

Tests schrijven

Test moet een essentieel onderdeel van alle code zijn en men moet zich richten op maximale testdekking. In dit artikel zullen we tests schrijven voor de routes die toegankelijk zijn vanuit onze applicatie. We zullen supertest en Mocha gebruiken om onze tests te maken. 

We zullen onze test opslaan in test.js in de api map. In beide tests beschrijven we eerst onze test, waardoor deze een menselijker leesbare naam krijgt. Hierna zullen we een anonieme functie doorgeven die het correcte gedrag van de test beschrijft en een callback nemen die de eigenlijke test bevat. In elke test importeren we onze applicatie, initiëren we de server, beschrijven we het aanvraagtype, de URL en de query en stellen we de codering in op gzip. Als laatste controleren we het antwoord als het correct is.

var request = require ('supertest'); var api = require ('... /index.js'); beschrijven ('GET all', function () it ('zou moeten reageren met alle woorden', functie (gereed) var app = api; request (app.listen ()) .get ('/ v1 / all') .query (word: 'new') .set ('Accept-Encoding', 'gzip') .expect ('Content-type', / json /) .expect (200) .end (done);) ) beschrijven ('GET / v1 / single', function () it ('zou moeten reageren met een enkel resultaat', functie (gereed) var app = api; request (app.listen ()) .get ('/ v1 / single ') .query (word:' new ') .set (' Accept-Encoding ',' gzip ') .expect (200) .expect (' Content-type ', / json /) .end ( functie (err, res) if (err) gooi err; else if (! ('_ id' in res.body)) geeft "missing id" terug; if (! ('word' in res.body)) gooit nieuw Fout ("ontbrekend woord"); done (););))

Als u onze test wilt uitvoeren, maken we een Makefile:

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

Hier hebben we de reporter (nyan cat) en het testraamwerk (mokka) geconfigureerd. Merk op dat de import zou moeten toevoegen --harmonie om de ES6-modus in te schakelen. Ten slotte specificeren we ook de locatie van alle tests. EEN Makefile kan worden geconfigureerd voor eindeloze testen van uw toepassing.

Om nu uw app te testen, gebruikt u gewoon de volgende opdracht in de hoofddirectory van de applicatie. 

$ maak een test

Vergeet niet om testmodules (mokka, should, supertest) te installeren voordat u gaat testen, met behulp van de onderstaande opdracht: 

$ npm installeer mokka moet mocha --save-dev 

Lopend in productie

Om onze applicaties in productie te houden, zullen we PM2 gebruiken, wat een nuttige Node procesmonitor is. We moeten de logger-app uitschakelen tijdens de productie; het kan worden geautomatiseerd met behulp van omgevingsvariabelen.

Om PM2 te installeren, voert u de volgende opdracht in terminal in

$ npm install pm2 -g 

En onze app kan worden gestart met behulp van de volgende opdracht:

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

Nu, zelfs als onze applicatie crasht, zal hij automatisch herstarten en kun je rustig slapen. 

Conclusie

Koa is een lichte en expressieve middleware voor Node.js die het proces van het schrijven van webtoepassingen en API's aangenamer maakt. 

Hiermee kunt u gebruikmaken van een groot aantal communitymodules om de functionaliteit van uw toepassing uit te breiden en alle alledaagse taken te vereenvoudigen, waardoor webontwikkeling een leuke activiteit wordt. 

Aarzel niet om opmerkingen, vragen of andere informatie in het onderstaande veld achter te laten.