Deno-Handbuch: Beispiele für die Arbeit mit der neuen serverseitigen JavaScript- und TypeScript-Laufzeit



Guten Tag, Freunde!



Ich präsentiere Ihnen die Übersetzung des Artikels "Das Deno-Handbuch: Ein TypeScript-Laufzeit-Tutorial mit Codebeispielen" von Flavio Copes.



In diesem Artikel lernen wir, wie man mit Deno arbeitet. Wir werden es mit Node.js vergleichen und damit eine einfache REST-API erstellen.



Was ist Deno?



Wenn Sie mit Node.js, dem beliebten serverseitigen JavaScript-Ökosystem, vertraut sind, ist Deno so ziemlich dasselbe. Fast, aber nicht ganz.



Beginnen wir mit einer Liste von Deno-Funktionen, die mir am besten gefallen:



  • Es basiert auf modernem JavaScript
  • Es verfügt über eine erweiterbare Standardbibliothek
  • Es bietet standardmäßige TypeScript-Unterstützung (dies bedeutet, dass Sie TypeScript nicht manuell kompilieren müssen, Deno erledigt dies automatisch).
  • Es unterstützt ES-Module
  • Es gibt keinen Paketmanager
  • Es hat eine globale await
  • Es verfügt über eine eingebaute Testeinrichtung
  • Das Ziel ist maximale Browserkompatibilität. Hierzu werden ein Inline- fetchund ein globales Objekt bereitgestelltwindow


In diesem Tutorial werden wir all diese Möglichkeiten untersuchen.



Nachdem Sie sich mit Deno und seinen Funktionen vertraut gemacht haben, wird Node.js etwas veraltet erscheinen.



Zumal Node.js auf Rückruffunktionen basiert (es wurde vor Versprechungen und async / await geschrieben). Es ist unwahrscheinlich, dass sie jemals dort erscheinen, da dies bedeutet, dass grundlegende Änderungen erforderlich sind.



Node.js ist großartig und wird der De-facto-Standard in der JavaScript-Welt bleiben. Ich glaube jedoch, dass Deno dank seiner TypeScript-Unterstützung und der modernen Standardbibliothek schnell an Popularität gewinnen wird.



Deno kann sich modernen Code leisten, da er keine Abwärtskompatibilität benötigt. Natürlich gibt es keine Garantie dafür, dass dieser Code im nächsten Jahrzehnt auf dem neuesten Stand bleibt, aber heute ist es so.



Warum Deno? Warum jetzt?



Deno wurde vor fast 2 Jahren von Node.js Schöpfer Ryan Dahl auf der JSConf EU angekündigt. Sehen Sie sich das YouTube-Video an , es ist sehr interessant und ein Muss, wenn Sie mit Node.js und JavaScript arbeiten.



Jeder Projektmanager (Ersteller) ist gezwungen, Entscheidungen zu treffen. Ryan bedauert einige der frühen Entscheidungen in Node. Darüber hinaus schreitet die Technologie voran und JavaScript ist heute eine völlig andere Sprache als 2009, als Node. Denken Sie an ES6 / 2016/2017 und so weiter zurück.



Also beschloss er, ein neues Projekt zu starten, eine Art zweite Welle serverseitiger JavaScript-Anwendungen.



Der Grund, warum ich diesen Artikel jetzt nur schreibe, ist, dass es ziemlich lange dauert, bis die Technologie ausgereift ist. Schließlich haben wir Deno 1.0 (es wurde am 13. Mai 2020 veröffentlicht), die erste stabile Version.



Dies mag wie eine übliche Zahl erscheinen, aber 1.0 bedeutet, dass es bis Deno 2.0 keine drastischen Änderungen geben wird. Wenn Sie neue Technologien erlernen, möchten Sie nicht, dass sie sich zu schnell ändern.



Solltest du Deno lernen?



Gute Frage.



Etwas Neues wie Deno zu lernen erfordert viel Mühe. Mein Rat: Wenn Sie gerade erst mit serverseitigem JS beginnen und Node.js noch nicht kennen und noch nie TypeScript geschrieben haben, beginnen Sie mit Node.



Bisher wurde noch niemand entlassen, weil er sich für Node entschieden hat (um ein berühmtes Zitat zu paraphrasieren).



Aber wenn Sie TypeScript mögen, das nicht von einer awaitMenge npm-Paketen abhängt und es überall verwenden möchte, ist Deno möglicherweise das, wonach Sie suchen.



Wird es Node.js ersetzen?



Nein. Node.js ist ein Riese, eine große Autorität, eine unglaublich gut unterstützte Technologie, die in den nächsten zehn Jahren nirgendwo hingehen wird.



Erstklassige TypeScript-Unterstützung



Deno ist in Rust und TypeScript geschrieben, beides sehr beliebte Sprachen in der heutigen Welt.



Dies bedeutet, dass TypeScript viele Vorteile bietet, selbst wenn wir JavaScript schreiben.



Das Ausführen von TypeScript-Code mit Deno erfordert keine Vorkompilierung - Deno führt dies automatisch durch.



Sie müssen keinen TypeScript-Code schreiben, aber die Tatsache, dass Denos Kern in TypeScript geschrieben ist, macht einen großen Unterschied.



Erstens liebt ein großer Prozentsatz der JavaScript-Entwickler TypeScript.



Zweitens können die von Ihnen verwendeten Tools viele Informationen über TypeScript-Software wie Deno erhalten.



Dies bedeutet, dass wir beispielsweise beim Schreiben von Code in VS-Code (der seit seiner Einführung eng in TypeScript integriert ist) Vorteile wie die Typprüfung beim Schreiben von Code oder erweiterte IntelliSense-Funktionen erhalten. Mit anderen Worten, die Hilfe des Code-Editors wird viel effizienter.



Unterschiede zu Node.js.



Da Deno im Wesentlichen ein Ersatz für Node.js ist, ist es sinnvoll, die beiden zu vergleichen.



Allgemeines:



  • Beide basieren auf dem V8-Motor
  • Beide eignen sich hervorragend für die serverseitige JavaScript-Entwicklung


Unterschiede:



  • Der Knoten ist in C ++ und JavaScript geschrieben. Deno ist in Rust und TypeScript geschrieben.
  • Node hat einen offiziellen Paketmanager npm. Deno hat keinen solchen Manager, stattdessen können Sie jedes Modul über eine URL importieren.
  • Der Knoten verwendet die CommonJS-Syntax zum Importieren von Paketen. Deno verwendet den offiziellen Weg - ES-Module.
  • Deno ECMAScript , Node.js .
  • Deno () . . Node.js , .
  • Deno , .. , , Go, . .




Das Fehlen eines Paketmanagers und die Verwendung einer URL zum Abrufen und Importieren von Paketen hat Vor- und Nachteile. Einer der Hauptvorteile ist die große Flexibilität, die mit der Möglichkeit verbunden ist, Pakete zu erstellen, ohne sie in einem Repository wie npm veröffentlichen zu müssen.



Ich denke, dass früher oder später eine Alternative zum Paketmanager in Deno auftauchen wird.



Auf der offiziellen Deno-Website werden Pakete von Drittanbietern gehostet: https://deno.land/x/



Deno installieren



Genug geredet! Lassen Sie uns Deno installieren.



Der einfachste Weg, dies zu tun, ist die Verwendung von Homebrew:



    brew install deno 






Andere Installationsmethoden sind hier aufgelistet .



Nach der Installation wird der Befehl verfügbar deno. Hier ist die Hilfe, die Sie durch Eingabe erhalten können deno --help:



flavio@mbp~> deno --help
deno 0.42.0
A secure JavaScript and TypeScript runtime

Docs: https://deno.land/std/manual.md
Modules: https://deno.land/std/ https://deno.land/x/
Bugs: https://github.com/denoland/deno/issues

To start the REPL, supply no arguments:
  deno

To execute a script:
  deno run https://deno.land/std/examples/welcome.ts
  deno https://deno.land/std/examples/welcome.ts

To evaluate code in the shell:
  deno eval "console.log(30933 + 404)"

Run 'deno help run' for 'run'-specific flags.

USAGE:
    deno [OPTIONS] [SUBCOMMAND]

OPTIONS:
    -h, --help
            Prints help information

    -L, --log-level <log-level>
            Set log level [possible values: debug, info]

    -q, --quiet
            Suppress diagnostic output
            By default, subcommands print human-readable diagnostic messages to stderr.
            If the flag is set, restrict these messages to errors.
    -V, --version
            Prints version information


SUBCOMMANDS:
    bundle         Bundle module and dependencies into single file
    cache          Cache the dependencies
    completions    Generate shell completions
    doc            Show documentation for a module
    eval           Eval script
    fmt            Format source files
    help           Prints this message or the help of the given subcommand(s)
    info           Show info about cache or info related to source file
    install        Install script as an executable
    repl           Read Eval Print Loop
    run            Run a program given a filename or url to the module
    test           Run tests
    types          Print runtime TypeScript declarations
    upgrade        Upgrade deno executable to newest version

ENVIRONMENT VARIABLES:
    DENO_DIR             Set deno's base directory (defaults to $HOME/.deno)
    DENO_INSTALL_ROOT    Set deno install's output directory
                         (defaults to $HOME/.deno/bin)
    NO_COLOR             Set to disable color
    HTTP_PROXY           Proxy address for HTTP requests
                         (module downloads, fetch)
    HTTPS_PROXY          Same but for HTTPS


Deno-Teams



Haben Sie den Abschnitt bemerkt SUBCOMMANDS? Dies ist eine Liste aller Befehle, die wir ausführen können. Welche Teams haben wir?



  • bundle - sammelt die Modul- und Projektabhängigkeiten in einer Datei
  • cache - Abhängigkeiten zwischenspeichern
  • completions - erzeugt Shell-Nachfüllungen
  • doc - zeigt die Dokumentation zum Modul
  • eval - wird zum Beispiel zum Berechnen eines Codeblocks verwendet deno eval "console.log(1 + 2)"
  • fmt- eingebauter Code-Formatierer (wie goFmtin Go)
  • help - Zeigt eine Liste der Hilfsbefehle an
  • info - Zeigt Informationen zum Cache oder zur Datei an
  • install - Setzt das Skript als ausführbar
  • repl - Lese-Rechen-Ausgabe-Zyklus (Standard)
  • run - führt das Programm mit dem angegebenen Namen oder der angegebenen URL für das Modul aus
  • test - führt Tests durch
  • types - Zeigt eine Liste der TypeScript-Funktionen an
  • upgrade - aktualisiert Deno auf die neueste Version


Sie können beispielsweise ausführen deno <subcommand> help, um Informationen zu einem bestimmten Befehl abzurufen deno run --help.



Wir können einen Befehl verwenden deno, um eine Lese-Auswertungs-Ausgabeschleife zu starten:







Dies ist dasselbe wie das Starten deno repl.



Typischerweise denoverwendet in einer Typoskript Datei enthielt eine Deno Anwendung zu starten.



Sie können sowohl TypeScript-Dateien (.ts) als auch JavaScript-Dateien (.js) ausführen.



Wenn Sie mit TypeScript nicht vertraut sind, machen Sie sich keine Sorgen: Deno ist in TypeScript geschrieben, aber Sie können Ihre Clientanwendungen in JavaScript schreiben.



Erste App auf Deno



Lassen Sie uns unsere erste Anwendung erstellen.



Dazu müssen wir nicht einmal Code schreiben, sondern führen ihn im Terminal unter Verwendung der URL aus.



Deno lädt das Programm herunter, kompiliert es und führt es aus:







Natürlich würde ich nicht empfehlen, zufälligen Code aus dem Internet auszuführen. In diesem Fall starten wir es von der offiziellen Deno-Website, und Deno verfügt über eine Sandbox, die verhindert, dass Programme das tun, was wir ihnen nicht ausdrücklich erlaubt haben.



Dieses Programm ist sehr einfach und ein Aufruf console.log():



console.log('Welcome to Deno ') //     ,    


Wenn Sie https://deno.land/std/examples/welcome.ts in einem Browser öffnen , wird Folgendes angezeigt:







Seltsam, nicht wahr? Sie haben wahrscheinlich erwartet, eine TypeScript-Datei zu sehen, haben aber stattdessen eine Webseite erhalten. Der Punkt ist, dass der Deno-Website-Server weiß, dass Sie einen Browser verwenden, und Ihnen eine benutzerfreundlichere Seite bietet.



Laden Sie zum Beispiel dieselbe URL mit wgetund erhalten Sie text/plainstattdessen text/html:







Wenn Sie das Programm neu starten, ist dank Caching kein Neustart erforderlich: Ein erzwungener Neustart kann







mit dem Flag durchgeführt werden --reload:







deno runhat viele verschiedene Funktionen, die von nicht angezeigt werden deno --help. Um sie zu sehen, sollten Sie Folgendes ausführen deno run --help:



flavio@mbp~> deno run --help
deno-run
Run a program given a filename or url to the module.

By default all programs are run in sandbox without access to disk, network or
ability to spawn subprocesses.
    deno run https://deno.land/std/examples/welcome.ts

Grant all permissions:
    deno run -A https://deno.land/std/http/file_server.ts

Grant permission to read from disk and listen to network:
    deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts

Grant permission to read whitelisted files from disk:
    deno run --allow-read=/etc https://deno.land/std/http/file_server.ts

USAGE:
    deno run [OPTIONS] <SCRIPT_ARG>...

OPTIONS:
    -A, --allow-all
            Allow all permissions

        --allow-env
            Allow environment access

        --allow-hrtime
            Allow high resolution time measurement

        --allow-net=<allow-net>
            Allow network access

        --allow-plugin
            Allow loading plugins

        --allow-read=<allow-read>
            Allow file system read access

        --allow-run
            Allow running subprocesses

        --allow-write=<allow-write>
            Allow file system write access

        --cached-only
            Require that remote dependencies are already cached

        --cert <FILE>
            Load certificate authority from PEM encoded file

    -c, --config <FILE>
            Load tsconfig.json configuration file

    -h, --help
            Prints help information

        --importmap <FILE>
            UNSTABLE:
            Load import map file
            Docs: https://deno.land/std/manual.md#import-maps
            Specification: https://wicg.github.io/import-maps/
            Examples: https://github.com/WICG/import-maps#the-import-map
        --inspect=<HOST:PORT>
            activate inspector on host:port (default: 127.0.0.1:9229)

        --inspect-brk=<HOST:PORT>
            activate inspector on host:port and break at start of user script

        --lock <FILE>
            Check the specified lock file

        --lock-write
            Write lock file. Use with --lock.

    -L, --log-level <log-level>
            Set log level [possible values: debug, info]

        --no-remote
            Do not resolve remote modules

    -q, --quiet
            Suppress diagnostic output
            By default, subcommands print human-readable diagnostic messages to stderr.
            If the flag is set, restrict these messages to errors.
    -r, --reload=<CACHE_BLACKLIST>
            Reload source code cache (recompile TypeScript)
            --reload
                Reload everything
            --reload=https://deno.land/std
                Reload only standard modules
            --reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts
                Reloads specific modules
        --seed <NUMBER>
            Seed Math.random()

        --unstable
            Enable unstable APIs

        --v8-flags=<v8-flags>
            Set V8 command line options. For help: --v8-flags=--help


ARGS:
    <SCRIPT_ARG>...
            script args


Codebeispiele



Es gibt andere Beispiele auf der Deno-Website, die hier zu finden sind .



Zum Zeitpunkt dieses Schreibens befand sich im angegebenen Repository Folgendes:



  • cat.ts - Zeigt den Inhalt von Dateien an, die als Argumente übergeben wurden
  • catj.ts- macht dasselbe, führt cat.tsaber zuerst einige Manipulationen mit dem Inhalt der Dateien durch
  • chat/ - Chat-Implementierung
  • colors.ts - Ein Beispiel für das Stylen von Text mithilfe von Modulen
  • curl.ts- Eine einfache Implementierung curl, die den Inhalt der als Argument übergebenen URL ausgibt
  • echo_server.ts - TCP-Echoserver
  • gist.ts - Programm zum Platzieren von Dateien in gist.github.com
  • test.ts - Testprogramm
  • welcome.ts - das Programm, das wir gestartet haben
  • xeval.ts- Ermöglicht die Ausführung von TypeScript aus einer beliebigen Standarddatenquelle. deno xevalwurde von der Liste der offiziellen Teams entfernt


Erste echte App auf Deno



Schreiben wir einen Code.



Die erste App, mit der wir gestartet sind, deno run https://deno.land/std/examples/welcome.tswurde bereits geschrieben, sodass Sie nichts Neues über Deno erfahren haben.



Beginnen wir mit einem Standardbeispiel auf der Deno-Website:



import { serve } from 'https://deno.land/std/http/server.ts'
const s = serve({ port: 8000 })
console.log('http://localhost:8000/')
for await (const req of s) {
    req.respond({ body: 'Hello World\n' })
}


Hier importieren wir eine Funktion serveaus einem Modul http/server. Sehen? Wir mussten es nicht installieren und es ist nicht wie Node-Module auf unserem Computer gespeichert. Dies ist einer der Gründe für die schnelle Installation von Deno.



Mit Hilfe https://deno.land/std/http/server.tsimportieren wir die neueste Version des Moduls. Eine bestimmte Version kann importiert werden mit @VERSION:



import { serve } from 'https://deno.land/std@v0.42.0/http/server.ts'


Dies ist, was die Funktion ist serve:



/**
 * Create a HTTP server
 *
 *     import { serve } from "https://deno.land/std/http/server.ts";
 *     const body = "Hello World\n";
 *     const s = serve({ port: 8000 });
 *     for await (const req of s) {
 *       req.respond({ body });
 *     }
 */
 export function serve(addr: string | HTTPOptions): Server {
  if (typeof addr === 'string') {
    const [hostname, port] = addr.split(':')
    addr = { hostname, port: Number(port) }
  }

  const listener = listen(addr)
  return new Server(listener)
}


Als nächstes rufen wir die Funktion auf serve()und übergeben ihr ein Objekt mit einer Eigenschaft port.



Wir führen dann eine Schleife aus, um auf jede Anfrage vom Server zu antworten:



for await (const req of s) {
  req.respond({ body: 'Hello World\n' })
}


Beachten Sie, dass wir das Schlüsselwort verwenden, awaitohne den Code in eine asyncFunktion einzuschließen.



Lassen Sie uns das Programm lokal ausführen. Ich verwende VS-Code, aber Sie können jeden Editor verwenden.



Ich empfehle die Installation einer Erweiterung von justjavac (es gibt eine andere mit einem ähnlichen Namen, die jedoch veraltet ist und möglicherweise in Zukunft verschwindet): Die







Erweiterung bietet verschiedene Dienstprogramme, mit denen Sie Deno-Anwendungen schreiben können.



Lassen Sie uns eine Datei erstellen app.tsund unseren Code einfügen:







Führen Sie ihn aus mit deno run app.ts:







Deno lädt alle Abhängigkeiten, die das Programm benötigt, aber zuerst die, die wir in die Datei importieren.



Die Datei https://deno.land/std/http/server.ts weist mehrere eigene Abhängigkeiten auf:



import { encode } from '../encoding/utf8.ts'
import { BufReader, BufWriter } from '../io/bufio.ts'
import { assert } from '../testing/asserts.ts'
import { deferred, Deferred, MuxAsyncIterator } from '../async/mod.ts'
import {
    bodyReader,
    chunkedBodyReader,
    emptyReader,
    writeResponse,
    readRequest,
} from './_io.ts'
import Listener = Deno.Listener
import Conn = Deno.Conn
import Reader = Deno.Reader


Diese Abhängigkeiten werden automatisch importiert.



Am Ende haben wir ein Problem:







Was ist los? Wir haben eine Erlaubnis verweigert Fehler.



Reden wir über den Sandkasten.



Sandkasten



Wie bereits erwähnt, verfügt Deno über eine Sandbox, die verhindert, dass Programme Dinge tun, für die sie nicht autorisiert wurden.



Was bedeutet das?



Wie Ryan in seinem Vortrag sagt, möchten Sie manchmal ein JavaScript-Programm außerhalb des Browsers ausführen, und Sie möchten nicht, dass das Programm auf alles auf Ihrem System zugreifen kann. Oder wenn es um die Nutzung des Netzwerks nach außen geht.



Nichts hindert die Anwendung Node.js daran, Ihren SSH-Schlüssel oder andere Informationen von Ihrem System abzurufen und an den Server zu senden. Aus diesem Grund installieren wir normalerweise nur Node-Pakete aus vertrauenswürdigen Quellen. Aber woher wissen wir, ob eines der von uns verwendeten Projekte gehackt wurde?



Deno ahmt das vom Browser verwendete Berechtigungssystem nach. JavaScript-Code, der in einem Browser ausgeführt wird, kann nichts mit Ihrem System tun, es sei denn, Sie erlauben dies ausdrücklich.



Zurück zu Deno: Wenn ein Programm Netzwerkzugriff benötigt, müssen wir ihm die Erlaubnis dazu erteilen.



Dies geschieht mit dem Flag --allow-net:



deno run --allow-net app.ts






Der Server läuft jetzt auf Port 8000:







Andere Flags:



  • --allow-env - Ermöglicht den Zugriff auf Umgebungsvariablen
  • --allow-hrtime - ermöglicht hochauflösende Messungen
  • --allow-net=<allow-net> - Ermöglicht den Zugriff auf das Netzwerk
  • --allow-plugin - Ermöglicht das Laden von Plugins
  • --allow-read=<allow-read> - Ermöglicht das Lesen von Dateien
  • --allow-run - Ermöglicht das Starten von Unterprozessen
  • --allow-write=<allow-write> - Ermöglicht das Schreiben von Dateien
  • --allow-all- erteilt alle Berechtigungen (ähnlich -A)


Berechtigungen für net, readund writekönnen teilweise sein. Beispielsweise können wir schreibgeschützte Dateien zulassen, die sich in einem bestimmten Verzeichnis befinden : --allow-read=/dev.



Code-Formatierung



Eines der Dinge, die ich an Go liebe, ist der Befehl gofmt. Der gesamte Go-Code sieht gleich aus. Jeder benutzt es gofmt.



JavaScript-Entwickler verwenden normalerweise Prettier und deno fmttatsächlich auch unter dem Schnitt.



Angenommen, Sie haben eine so schlecht formatierte Datei:







Sie starten deno fmt app.tsund die automatische Formatierung erfolgt mit fehlenden Semikolons:







Standardbibliothek



Die Standardbibliothek von Deno ist trotz des Alters des Projekts ziemlich umfangreich.



Es enthält Folgendes:



  • archieve - Dienstprogramme zur Archivierung
  • async - Dienstprogramme für die Arbeit mit asynchronem Code
  • bytes - Hilfsfunktionen zum Aufteilen von Bytes
  • datetime - Analysieren von Daten / Zeiten
  • encoding - Kodierung / Dekodierung in verschiedenen Formaten
  • flags - Parsing von Befehlszeilenflags
  • fmt - Bildung und Anzeige
  • fs - Anwendungsschnittstelle für die Arbeit mit dem Dateisystem
  • hash - Verschlüsselungsbibliothek
  • http - HTTP-Server
  • io - Bibliothek von Eingabe- / Ausgabeoperationen
  • log - Dienstprogramme für die Protokollierung
  • mime - Unterstützung gemischter Daten
  • node - Abwärtskompatibilitätsschicht mit Knoten
  • path - mit Pfaden arbeiten
  • ws - Web-Sockets


Noch ein Beispiel



Schauen wir uns ein anderes offizielles Beispiel an cat.ts:



const filenames = Deno.args
for (const filename of filenames) {
    const file = await Deno.open(filename)
    await Deno.copy(file, Deno.stdout)
    file.close()
}


Wir weisen einer Variablen filenamesInhalt zu. Dies Deno.argsist eine Variable, die die über die Befehlszeile übergebenen Argumente enthält.



Wir iterieren über sie und verwenden sie jeweils Deno.open()zum Öffnen der Datei und zum Deno.copy()Kopieren des Inhalts Deno.stdout. Zum Schluss schließen wir die Datei.



Wenn du läufst:



deno run https://deno.land/std/examples/cat.ts


Das Programm wird geladen und kompiliert, aber es passiert nichts, da wir keine Argumente übergeben haben.



Versuchen wir Folgendes:



deno run https://deno.land/std/examples/cat.ts app.ts


Wir







erhalten einen Berechtigungsfehler: Deno hat standardmäßig keinen Zugriff auf das System. Erteilen wir ihm diese Erlaubnis mit --allow-read:



deno run --allow-read=./ https://deno.land/std/examples/cat.ts app.ts






Gibt es Express / Hapi / Koa / * für Deno?



Ja natürlich. Schauen Sie sich folgende Projekte an:





Beispiel: Verwenden von Oak zum Erstellen einer REST-API



Ich werde eine REST-API mit Oak erstellen. Oak ist insofern interessant, als es von Koa, einer beliebten Middleware für NOde.js, inspiriert ist und eine ähnliche Syntax aufweist.



Unsere API wird sehr einfach sein.



Unser Server speichert eine Liste der Hunde, deren Namen und Alter.



Wir möchten folgende Funktionalität erhalten:



  • füge neue Hunde zur Liste hinzu
  • Holen Sie sich eine Liste aller Hunde
  • Informationen über einen bestimmten Hund erhalten
  • Entfernen Sie einen Hund von der Liste
  • Aktualisieren Sie das Alter des Hundes


Wir werden den Code in Typescript schreiben, aber nichts hindert Sie daran, ihn in JavaScript auszuführen - geben Sie nur nicht die Datentypen an.



Wir erstellen eine Datei app.ts.



Beginnen wir mit dem Importieren von Objekten nach Applicationund Routervon Oak:



import { Application, Router } from 'https://deno.land/x/oak/mod.ts'


Wir erhalten die Umgebungsvariablen PORT und HOST:



const env = Deno.env.toObject()
const PORT = env.PORT || 4000
const HOST = env.HOST || '127.0.0.1'


Standardmäßig wird unsere Anwendung auf localhost ausgeführt: 4000.



Erstellen Sie eine Oak-Anwendung und starten Sie sie:



const router = new Router()

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Listening on port ${PORT}...`)

await app.listen(`${HOST}:${PORT}`)


Die Anwendung sollte jetzt funktionieren.



Wir überprüfen:



deno run --allow-env --allow-net app.ts


Deno lädt Abhängigkeiten herunter:







und beginnt, Port 4000 abzuhören.



Beim Neustart wird der Installationsschritt dank Caching übersprungen:







Definieren Sie eine Schnittstelle für den Hund und definieren Sie dann ein Array, dogdas die Objekte enthält Dog:



interface Dog {
  name: string
  age: number
}

let dogs: Array<Dog> = [
  {
    name: 'Roger',
    age: 8,
  },
  {
    name: 'Syd',
    age: 7,
  },
]


Beginnen wir mit der Implementierung der API.



Alles ist an Ort und Stelle. Fügen wir dem Router mehrere Funktionen hinzu, die beim Zugriff auf den angegebenen Endpunkt aufgerufen werden:



const router = new Router()

router
    .get('/dogs', getDogs)
    .get('/dogs/:name', getDog)
    .post('/dogs', addDog)
    .put('/dogs/:name', updateDog)
    .delete('/dogs/:name', removeDog)


Wir haben Folgendes definiert:



  • GET /dogs
  • GET /dogs/:name
  • POST /dogs
  • PUT /dogs/:name
  • DELETE /dogs/:name




Lassen Sie uns diese Routen einzeln implementieren.



Beginnen wir mit GET /dogseiner Liste aller Hunde:



export const getDogs = ({ response }: { response: any }) => {
    response.body = dogs
}






So erhalten Sie einen bestimmten Hund mit Namen:



export const getDog = ({
  params,
  response,
}: {
    params: {
        name: string
    },
    response: any
}) => {
    const dog = dogs.filter(dog => dog.name === params.name)
    if (dog.length) {
        response.status = 200
        response.body = dog[0]
        return
    }

    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
}






So fügen Sie der Liste einen neuen Hund hinzu:



export const addDog = async ({
    request,
    response,
}: {
    request: any
    response: any
}) => {
    const body = await request.body()
    const dog: Dog = await body.value
    dogs.push(dog)

    response.body = { msg: 'OK' }
    response.status = 200
}






So aktualisieren Sie das Alter Ihres Hundes:



export const updateDog = async ({
    params,
    request,
    response,
}: {
    params: {
        name: string
    },
    request: any
    response: any
}) => {
    const temp = dogs.filter((existingDog) => existingDog.name === params.name)
    const body = await request.body()
    const { age }: { age: number } = await body.value

    if (temp.length) {
        temp[0].age = age
        response.status = 200
        response.body = { msg: 'OK' }
        return
    }

    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
}






Und so entfernen Sie einen Hund von der Liste:



export const removeDog = ({
    params,
    response,
}: {
    params: {
        name: string
    },
    response: any
}) => {
    const lengthBefore = dogs.length
    dogs = dogs.filter((dog) => dog.name !== params.name)

    if (dogs.length === lengthBefore) {
        response.status = 400
        response.body = { msg: `Cannot find dog ${params.name}` }
        return
    }

    response.body = { msg: 'OK' }
    response.status = 200
}






Vollständiger Anwendungscode:



import { Application, Router } from 'https://deno.land/x/oak/mod.ts'

const env = Deno.env.toObject()
const PORT = env.PORT || 4000
const HOST = env.HOST || '127.0.0.1'

interface Dog {
  name: string
  age: number
}

let dogs: Array<Dog> = [
  {
    name: 'Roger',
    age: 8,
  },
  {
    name: 'Syd',
    age: 7,
  },
]

export const getDogs = ({ response }: { response: any }) => {
  response.body = dogs
}

export const getDog = ({
  params,
  response,
}: {
  params: {
    name: string
  },
  response: any
}) => {
  const dog = dogs.filter(dog => dog.name === params.name)
  if (dog.length) {
    response.status = 200
    response.body = dog[0]
    return
  }

  response.status = 400
  response.body = { msg: `Cannot find dog ${params.name}` }
}

export const addDog = async ({
  request,
  response,
}: {
  request: any
  response: any
}) => {
  const body = await request.body()
  const { name, age }: { name: string; age: number } = await body.value
  dogs.push({
    name: name,
    age: age,
  })

  response.body = { msg: 'OK' }
  response.status = 200
}

export const updateDog = async ({
  params,
  request,
  response,
}: {
  params: {
    name: string
  },
  request: any
  response: any
}) => {
  const temp = dogs.filter((existingDog) => existingDog.name === params.name)
  const body = await request.body()
  const { age }: { age: number } = await body.value

  if (temp.length) {
    temp[0].age = age
    response.status = 200
    response.body = { msg: 'OK' }
    return
  }

  response.status = 400
  response.body = { msg: `Cannot find dog ${params.name}` }
}

export const removeDog = ({
  params,
  response,
}: {
  params: {
    name: string
  },
  response: any
}) => {
  const lengthBefore = dogs.length
  dogs = dogs.filter(dog => dog.name !== params.name)

  if (dogs.length === lengthBefore) {
    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
    return
  }

  response.body = { msg: 'OK' }
  response.status = 200
}

const router = new Router()
router
  .get('/dogs', getDogs)
  .get('/dogs/:name', getDog)
  .post('/dogs', addDog)
  .put('/dogs/:name', updateDog)
  .delete('/dogs/:name', removeDog)

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Listening on port ${PORT}...`)

await app.listen(`${HOST}:${PORT}`)


Danke für die Aufmerksamkeit.