Deno 環境下的 TypeScript 開發

做者:Flavio Copes

翻譯:瘋狂的技術宅javascript

原文:https://www.freecodecamp.org/...html

未經容許嚴禁轉載前端

The Deno Handbook: A TypeScript Runtime Tutorial with Code Examples

我每週都會探索一些新的項目,但不多會有像 Deno 這樣吸引個人。java

在本文中,我會讓你快速瞭解 Deno,並把它與 Node.js 進行比較,以此構建你的第一個 REST API。node

什麼是Deno?

Deno 就像 Node,可是在不少方面都獲得了深刻的改善。先從 Deno 功能列表開始:git

  • 它基於 JavaScript 語言的現代功能
  • 它有全面的標準庫
  • 它以 TypeScript 爲核心,以許多不一樣的方式帶來了巨大的優點,包括一流的 TypeScript 支持(你沒必要單獨編譯 TypeScript,它由 Deno 自動完成)
  • 它包含 ES 模塊
  • 沒有包管理器
  • 它有一流的 await
  • 內置測試功能
  • 它儘量地與瀏覽器保持兼容,例如提供內置的 fetch 和全局 window 對象

咱們將在本指南中探索全部這些功能。程序員

在你開始使用 Deno 並瞭解了其功能以後,Node.js 看起來就像是「舊的」東西。github

特別是由於 Node.js API 是基於回調的,它是在 promise 和 async/await以前編寫的。 Node 中沒有可用於修改的餘地,這種修改的代價將會是巨大的。因此咱們只能用回調或大量的 API 調用。web

Node.js 很是棒,並將繼續成爲 JavaScript 世界中事實上的標準。可是我想咱們會逐漸看到 Deno 因爲其一流的 TypeScript 支持和現代標準庫而愈來愈被普遍的採用。面試

因爲沒有向後兼容性的報復,因此 Deno 能夠用現代技術編寫全部的東西。固然咱們沒法保證十年以內在 Deno 身上也會發生一樣的事情,而且會出現一項新技術,但這是目前的現實。

爲何是 Deno?爲何是如今?

大約2年前,Node.js 的原始建立者 Ryan Dahl 在 JSConf EU 上宣佈了 Deno(油管上的演講視頻),這很是有趣,若是你常常用 Node.js 和 JavaScript,那麼它是必看的。

每一個項目經理都必須作出決定。 Ryan 對 Node 中的一些早期決定感到遺憾。此外,技術也在不斷髮展,現在的 JavaScript 與 2009 年 Node 創立時的語言已經徹底不一樣。好比現代的 ES6/2016/2017 功能等。

因此他開始了一個新項目,用來建立第二波基於 JavaScript 的服務器端程序。

我如今而不是兩年前寫本文的緣由是,技術須要大量時間才能成熟。咱們終於達到了 Deno 1.0(1.0 在2020年5月13日發佈),這是 Deno 正式宣佈穩定的初版。

這彷佛只是一個數字,但 1.0 表示直到 Deno 2.0 纔會有重大突破。當你採用一種新技術時,這很重要——你不想學習某些東西,由於它改變得太快。

你應該學習Deno嗎?

這是一個大問題。

學習諸如 Deno 之類的新東西須要很大的努力。個人建議是,若是你如今開始使用服務器端 JS,而且還不瞭解 Node,而且從未編寫過任何 TypeScript 代碼,那麼就從 Node 開始。沒有人由於選擇 Node.js 而被解僱。

可是,若是你喜歡 TypeScript,想要在任何地方使用 await,但不想依賴項目中龐大的 npm 包,那麼 Deno 可能就是你想要的。

它會取代 Node.js 嗎?

答案是否認的。Node.js 是一項龐大的、完善的、得到了良好支持的技術,它將會持續數十年。

一流的TypeScript支持

Deno 用 Rust 和 TypeScript 編寫,這兩種語言今天正在迅速發展。

特別是使用 TypeScript 意味着即便咱們選擇用純 JavaScript編寫代碼,也能夠得到 TypeScript 的不少好處。

使用 Deno 運行 TypeScript 代碼不須要編譯步驟——Deno 會自動爲你執行這一步驟。

你不會被迫使用 TypeScript 編寫代碼,可是 Deno 的核心是用 TypeScript 編寫的這一事實是明顯的。

首先愈來愈多的 JavaScript 程序員開始喜歡 TypeScript。

其次,你使用的工具能夠推斷出許多有關用 TypeScript 編寫的軟件的信息,例如 Deno。

這意味着,當咱們用 VS Code 進行編碼時(因爲兩者都是在 MicroSoft 上開發的,所以與 TypeScript 緊密集成),能夠在編寫代碼時得到類型檢查和高級 IntelliSense 功能。換句話說,編輯器可以以很是有用的方式幫助咱們。

與 Node.js 的異同

因爲 Deno 基本上是 Node.js 的替代品,因此直接對二者比較很是有用。

類似之處:

  • 二者都是基於 V8 Chromium Engine 開發的
  • 二者都很是適合用 JavaScript 開發服務器端

差別:

  • Node 用 C++ 和 JavaScript 編寫。 Deno 用 Rust 和 TypeScript 編寫。
  • Node 有一個名爲 npm 的官方包管理器。 Deno 沒有,而是讓你從 URL 導入任何 ES 模塊。
  • Node 使用 CommonJS 語法導入 pacakges。 Deno 使用官方的 ES 模塊。
  • Deno 在其全部 API 和標準庫中使用現代 ECMAScript 功能,而 Node.js 使用基於回調的標準庫,而且沒有計劃對其進行升級。
  • Deno 經過權限提供了一個沙箱安全層。程序只能訪問由用戶設置爲可執行文件的權限做爲標誌。 Node.js 程序能夠訪問用戶有權訪問的任何內容。
  • Deno 長期以來一直在考慮將程序編譯成可執行文件的可能性,而這種可執行文件能夠在沒有外部依賴項的狀況下運行,就像 Go 同樣,不過如今尚未正式提上日程。這將改變遊戲規則。

沒有包管理器

沒有包管理器而且必須依靠 URL 來承載和導入包有利有弊。我真的很喜歡 pros:它很是靈活,咱們能夠建立軟件包而無需將其發佈到 npm 這樣的存儲庫中。

我認爲會有某種包管理器出現,可是尚未官方的消息。

Deno 網站爲第三方軟件包提供代碼託管(並經過 URL 分發):https://deno.land/x/

安裝 Deno

聊的夠多了!下面開始安裝 Deno。

在 Mac 上最簡單的方法是用 Homebrew

brew install deno

img

一旦完成,你將能夠訪問 deno 命令。下面是你能夠用 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 命令

請注意幫助中的 SUBCOMMANDS 部分,其中列出了咱們能夠運行的全部命令。都有哪些子命令呢?

  • bundle 把模塊和項目的依賴關係打包到單個文件中
  • cache 緩存依賴項
  • completions 生成 shell 補全
  • doc 顯示模塊的文檔
  • eval 用來評估一段代碼,例如 deno eval "console.log(1 + 2)"
  • fmt 內置的代碼格式化程序(相似於 Go 中的 gofmt
  • help 打印此消息或給定子命令的幫助
  • info顯示有關緩存的信息或與源文件有關的信息
  • install 把腳本做爲可執行文件進行安裝
  • repl 讀取評估打印循環(默認)
  • run 運行爲模塊指定文件名或 URL 的程序
  • test 運行測試
  • types 打印運行時 TypeScript 聲明
  • upgrade upgrade deno to the newest version
  • upgrade 升級到最新版本的 deno

能夠運行 deno help 來獲取命令的特定其餘說明,例如 deno run --help

就像幫助所說的那樣,咱們能夠用這個命令使 deno 來啓動REPL(Read-Execute-Print-Loop),而無需任何其餘操做。

img

這與運行 deno repl 相同。

這個命令的一種更常見的使用方法是執行包含在 TypeScript 文件中的 Deno 程序。

你能夠同時運行 TypeScript(.ts)文件與 JavaScript(.js)文件。

若是你不熟悉 TypeScript,請不要擔憂:儘管 Deno 是用 TypeScript 編寫的,可是你也能夠用 JavaScript 編寫「客戶端」程序。

第一個 Deno 程序

讓咱們運行第一個 Deno 應用程序。

我感到很是驚奇的是,甚至不須要寫一行代碼代碼——你能夠從任何 URL 運行命令。

Deno下載程序,進行編譯,而後運行:

img

固然,從互聯網上運行任意代碼不是一種建議作法。不過咱們是從 Deno 官方網站上運行它的,另外,Deno 還有一個沙箱,能夠阻止程序執行你不但願作的任何事情。稍後再詳細介紹。

這個程序很是簡單,只需調用 console.log() 便可:

console.log('Welcome to Deno 🦕')

若是用瀏覽器打開 URL https://deno.land/std/example... ,則會看到如下頁面:

img

奇怪吧?你可能但願拿到 TypeScript 文件,可是卻獲得了一個網頁。緣由是 Deno 網站的 Web 服務器知道你正在使用瀏覽器,併爲你提供了更加用戶友好的頁面。

例如,用 wget 下載相同的UR,它要求使用 text/plain 版本而不是 text/html

img

若是你想再次運行該程序,那麼如今它已由 Deno 緩存,不須要再次下載:

img

你可使用 `--reload 標誌來強制從新加載原始源:

img

deno run 有許多沒有在 deno --help 中列出的選項。你須要運行 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

Deno 代碼示例

除了上面運行的示例外,Deno 網站還提供了一些其餘例子,你能夠在這找到它們:https://deno.land/std/examples/

在撰寫本文時,咱們能夠找到:

  • cat.ts: 打印做爲參數提供的文件列表的內容
  • catj.ts: 打印做爲參數提供的文件列表的內容
  • chat/: 一個聊天程序的實現
  • colors.ts: 一個例子
  • curl.tscurl的簡單實現,可打印做爲參數輸入的 URL 的內容
  • echo_server.ts: 一個 TCP 回顯服務器
  • gist.ts:一個將文件發佈到 gist.github.com 的程序
  • test.ts:測試的例子
  • welcome.ts:一個簡單的 console.log 語句(咱們在上面運行的第一個程序)
  • xeval.ts 容許你爲收到的任何標準輸入行運行任何 TypeScript 代碼。 曾經是 deno xeval 命令,但此後已從官方命令中刪除。

你本身的第一個 Deno 程序

讓咱們寫一些代碼。

你使用 deno run https://deno.land/std/examples/welcome.ts 運行的 Deno 程序是別人寫的,因此你對 Deno 代碼的樣子一無所知。

咱們將從 Deno 官方網站上列出的默認示例開始:

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

該代碼從 http/server 模塊導入 serve 函數。看到沒?咱們沒必要事先安裝它,也不會像 Node 模塊那樣將其存儲在本地計算機上。這是 Deno 安裝如此之快的緣由之一。

https://deno.land/std/http/se... 會導入模塊的最新版本。你可使用 @VERSION 導入特定版本,以下所示:

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

在這個文件中,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)
}

咱們繼續實例化一個調用 serve() 函數的服務器,該服務器傳遞帶有 port 屬性的對象。

而後,咱們運行這個循環來響應來自服務器的每一個請求。

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

請注意,因爲 Deno 實現了 top-level await,所以無需使用 await 關鍵字便可將其包裝到 async 函數中。

讓咱們在本地運行該程序。假設你用的是 VS Code,不過你可使用任何喜歡的編輯器。

我建議從 justjavac 安裝 Deno 擴展(我嘗試時有另外一個名稱相同,但已棄用的擴展——未來可能會消失)

img

該擴展將提供一些可以給 VS Code 帶來好處的實用工具,幫助你編寫程序。

下面在文件夾中建立一個 app.ts 文件,並粘貼上面的代碼:

img

而後用 deno run app.ts 運行:

img

Deno 首先下載咱們導入的依賴項,而後再下載所需的全部依賴項。

https://deno.land/std/http/se... 文件自己有多個依賴項:

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

而且這些都是自動導入的。

儘管最後咱們遇到了一個問題:

img

怎麼回事?咱們遇到了一個權限被拒絕的問題。

接下來要談談沙箱。

Deno 沙箱

以前我曾經提到過,Deno 的沙箱能夠防止程序執行你不但願作的任何事情。

這是什麼意思?

Ryan 在 Deno 簡介演講中提到過,有時你想在 Web 瀏覽器以外運行 JavaScript 程序,但又不想讓它訪問系統上任何內容,或使用網絡與外界對話。

沒有什麼方法可以阻止 Node.js 應用獲取你係統上的 SSH 密鑰或任何其餘的東西,並將其發送到服務器。這就是爲何咱們一般只從受信任的源安裝 Node 軟件包的緣由。可是,咱們怎麼知道本身使用的項目是否遭到黑客入侵,而其餘人是否被黑客入侵呢?

Deno 嘗試複製與瀏覽相同的權限模型。除非你明確容許,不然在瀏覽器中運行的 JavaScript 不會在你的系統上作任何使人做嘔的事情。

回到 Deno,若是一個程序想要像之前那樣訪問網絡,那麼咱們須要給它權限。

能夠經過在運行命令時傳遞一個標誌來實現,在本例中是 --allow-net

deno run --allow-net app.ts

img

如今該程序能夠在端口 8000 上運行 HTTP 服務器了:

img

有不少容許 Deno 解鎖其餘功能的標誌:

  • --allow-env 容許環境訪問
  • --allow-hrtime 容許高精度的時間測量
  • --allow-net = 容許網絡訪問
  • --allow-plugin 容許加載插件
  • --allow-read = 容許文件系統讀訪問
  • --allow-run 容許運行子進程
  • --allow-write =容許文件系統寫訪問
  • --allow-all 容許全部權限(與 -A 相同)

netreadwrite 的權限能夠是細粒度的。例如你能夠用 --allow-read=/dev 來容許從特定目錄中讀取

格式化代碼

我喜歡 Go 語言的一個緣由是 Go 編譯器附帶的 gofmt 命令。全部的 Go 代碼看起來都同樣。每一個人都在用 gofmt

JavaScript 程序員習慣於運行 Prettierdeno fmt 其實是在後臺運行的。

假設你有一個格式很亂的文件,以下所示:

img

運行 deno fmt app.ts,它會自動被正確的格式化,還會在缺乏分號的地方自動添加:

img

標準庫

儘管這個項目還很年輕,但 Deno 的標準庫仍然很龐大。

其中包括:

  • archive: tar 存檔工具
  • async async utilties
  • async:異步工具
  • bytes:用來操做字節片斷的輔助
  • datetime: 日期/時間解析
  • encoding :各類格式的編碼/解碼功能
  • flags: 解析命令行標誌
  • fmt: 格式化和打印
  • fs:文件系統 API
  • hash:加密庫
  • http: HTTP服務器
  • io: I/O 庫
  • log: 日誌實用工具
  • mime:支持 multipart 數據
  • node: Node.js 兼容性層
  • path:路徑操做
  • ws: websockets

另外一個Deno示例

讓咱們查看另外一個 Deno 應用示例:cat

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

這會將 Deno.args 的內容賦值給 filenames 變量,這一變量是包含發送到命令的全部參數的變量。

咱們遍歷它們,對於每個文件名咱們都用 Deno.open()打開文件,而後使用 Deno.copy() 將文件的內容打印到 Deno.stdout。最後關閉文件。

若是你這樣執行:

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

那麼該程序會被下載並編譯,但沒有任何反應,由於咱們沒有指定任何參數。

如今試試

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

假設你在同一文件夾中有上一個項目的 app.ts,會看到權限錯誤:

img

由於在默認狀況下 Deno 是不容許訪問文件系統的。使用 --allow-read=./ 能夠授予對當前文件夾的訪問權限:

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

img

Deno 是否有 Express/Hapi/Koa ?

固然有相似的項目:

示例:使用 Oak 構建 REST API

我想舉一個簡單的例子,說明如何用 Oak 構建 REST API。 Oak 之因此有趣,是由於它受到了流行的 Node.js 中間件 Koa 的啓發,所以,若是你之前用過,將會很是熟悉。

要構建的API很是簡單。咱們的服務器將會在內存中存儲帶有名稱和年齡的狗的列表。

咱們想:

  • 添加新狗
  • 列出狗
  • 獲取特定狗的詳細信息
  • 從列表中刪除一條狗
  • 更新狗的年齡

咱們將用 TypeScript 進行這些操做,固然你也能夠用 JavaScript 編寫 API —— 只需去掉類型就能夠了。

建立一個 app.ts 文件。

首先從 Oak 導入 ApplicationRouter 對象:

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

而後獲得環境變量 PORT 和 HOST:

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

默認狀況下,咱們的程序將運行在 localhost:4000 上。

接下來建立 Oak 應用程序並啓動它:

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}`)

如今程序應該能夠正常編譯了。

運行

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

而後 Deno 將會下載依賴項:

img

最後偵聽 4000 端口。

下次運行命令時,Deno 將會跳過安裝部分,由於這些軟件包已經被緩存了:

img

在文件開始,咱們爲狗定義一個接口,而後聲明一個初始的 Dog 對象 dogs 數組:

interface Dog {
  name: string
  age: number
}

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

如今開始實現 API。

準備就緒。在建立路由器後,讓咱們添加一些將被調用的功能:

const router = new Router()

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

看到了嗎?咱們定義瞭如下這些:

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

讓咱們一一實現。

GET/dogs 開始,它返回全部狗的列表:

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

img

接下來,是經過名稱檢索一隻狗的方法:

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

img

這是咱們添加新 dog 的方法:

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

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

img

注意,我如今使用 const body = await request.body() 來獲取 body 的內容,由於 nameage 的值是做爲 JSON 傳遞的。

這是更新狗年齡的方法:

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 } = 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}` }
}

img

這是從列表中刪除狗的方法:

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
}

img

如下是完整的代碼:

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 } = 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 } = 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}`)

更多資源

Deno 官方網站是 https://deno.land

可在 https://doc.deno.landhttps://deno.land/typedoc/ind... 上獲得 API 文檔。

awesome-deno https://github.com/denolib/aw...

一些小花絮

  • Deno 提供了一個內置的 fetch 實現,與瀏覽器中的相匹配
  • Deno 與 Node.js stdlib 有一個兼容層正在進行開發中

最後的話

但願你喜歡這個 Deno 教程!


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索