Denoガイド:新しいサーバー側JavaScriptおよびTypeScriptランタイムの操作例



良い一日、友達!Flavio Copesによる



記事「TheDenoHandbook:A TypeScript Runtime Tutorial withCodeExamples」の翻訳を紹介します



この記事では、Denoの操作方法を学習します。これをNode.jsと比較し、それを使用して単純なRESTAPIを構築します。



デノとは?



人気のあるサーバー側のJavaScriptエコシステムであるNode.jsに精通している場合、Denoはほとんど同じです。ほとんどですが、完全ではありません。



私が最も好きなDeno機能のリストから始めましょう:



  • 最新のJavaScriptに基づいています
  • 拡張可能な標準ライブラリがあります
  • 標準のTypeScriptサポートがあります(つまり、TypeScriptを手動でコンパイルする必要はなく、Denoが自動的にコンパイルします)
  • ESモジュールをサポートします
  • パッケージマネージャーはありません
  • それはグローバルです await
  • テスト機能が組み込まれています
  • その目標は、最大のブラウザー互換性です。このために、インラインfetchオブジェクトとグローバルオブジェクトを提供しますwindow


このチュートリアルでは、これらすべての可能性を探ります。



Denoとその機能に慣れると、Node.jsは少し時代遅れになります。



特にNode.jsはコールバック関数に基づいているため(promiseおよびasync / awaitの前に記述されています)。根本的な変更が必要であることを意味するため、それらがそこに表示される可能性はほとんどありません。



Node.jsは素晴らしく、JavaScriptの世界では事実上の標準であり続けるでしょう。ただし、TypeScriptのサポートと最新の標準ライブラリのおかげで、Denoの人気は急速に高まると思います。



Denoは、下位互換性を必要としないため、最新のコードを購入できます。もちろん、このコードが今後10年間最新であるという保証はありませんが、今日ではそうです。



なぜデノ?なぜ今なのか?



Denoは、ほぼ2年前にJSConfEUでNode.jsの作成者であるRyanDahlによって発表されました。見るYouTubeの動画を、それは非常に興味深く、必見のNode.jsとJavaScriptであなたがしている作業している場合です。



各プロジェクトマネージャー(作成者)は、決定を下すことを余儀なくされています。ライアンは、ノードでの初期の決定のいくつかを後悔しています。さらに、テクノロジーが進歩し、JavaScriptは、ノードが2009年にあったときとはまったく異なる言語になりました。 ES6 / 2016/2017などを思い出してください。



そこで彼は、サーバー側のJavaScriptアプリケーションの一種である新しいプロジェクトを開始することにしました。



私が今この記事を書いているのは、テクノロジーが成熟するまでにかなり長い時間がかかるからです。最後に、最初の安定したリリースであるDeno 1.0(2020年5月13日にリリースされました)を入手しました。



これは一般的な数字のように思えるかもしれませんが、1.0は、Deno2.0まで大幅な変更がないことを意味します。新しいテクノロジーを学ぶとき、それがあまりにも速く変化することを望まないでしょう。



あなたはデノを学ぶべきですか?



良い質問。



デノのような新しいことを学ぶには多くの努力が必要です。私のアドバイス:サーバー側のJSを使い始めたばかりで、Node.jsをまだ知らず、TypeScriptを作成したことがない場合は、Nodeから始めてください。



ノードを選択したことで解雇されたことはありません(有名な引用を言い換えます)。



しかし、大量のnpmパッケージに依存しないTypeScriptが好きで、どこでも使用したいawait場合は、Denoが探しているかもしれません。



Node.jsに取って代わりますか?



番号。Node.jsは巨大で大きな権威であり、信じられないほど十分にサポートされているテクノロジーであり、今後10年間は​​どこにも行きません。



ファーストクラスのTypeScriptサポート



DenoはRustとTypeScriptで書かれており、どちらも今日の世界で非常に人気のある言語です。



これは、JavaScriptを作成している場合でも、TypeScriptから多くのメリットが得られることを意味します。



DenoでTypeScriptコードを実行する場合、事前コンパイルは必要ありません-Denoはこれを自動的に実行します。



TypeScriptコードを作成する必要はありませんが、DenoのコアがTypeScriptで作成されているという事実は大きな違いを生みます。



まず、JavaScript開発者の大部分がTypeScriptを愛しています。



次に、使用するツールは、DenoのようなTypeScriptで記述されたソフトウェアに関する多くの情報を取得できます。



つまり、たとえばVS Code(最初からTypeScriptと緊密に統合されている)でコードを作成すると、コード作成時の型チェックや高度なIntelliSense機能などのメリットが得られます。言い換えれば、コードエディタの助けがはるかに効率的になります。



Node.jsとの違い



Denoは本質的にNode.jsの代替であるため、2つを比較することは理にかなっています。



一般:



  • どちらもV8エンジンに基づいています
  • どちらもサーバー側のJavaScript開発に最適です


違い:



  • ノードはC ++とJavaScriptで書かれています。DenoはRustとTypeScriptで書かれています。
  • ノードには公式のパッケージマネージャーがありnpmます。Denoにはそのようなマネージャーはありませんが、代わりにURLを使用して任意のモジュールをインポートできます。
  • NodeはCommonJS構文を使用してパッケージをインポートします。Denoは公式の方法であるESモジュールを使用します。
  • Deno ECMAScript , Node.js .
  • Deno () . . Node.js , .
  • Deno , .. , , Go, . .




パッケージマネージャーがなく、URLを使用してパッケージを取得およびインポートすることには、長所と短所があります。主な利点の1つは、npmなどのリポジトリにパッケージを公開しなくてもパッケージを作成できる柔軟性が高いことです。



遅かれ早かれ、デノのパッケージマネージャーに代わるものが登場すると思います。



Denoの公式ウェブサイトはサードパーティのパッケージをホストしています:https//deno.land/x/



Denoのインストール



十分に話します!Denoをインストールしましょう。



これを行う最も簡単な方法は、Homebrewを使用することです。



    brew install deno 






その他のインストール方法はここにリストされています



インストール後、コマンドが使用可能になります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


デノチーム



セクションに気づきましたSUBCOMMANDSか?これは、実行できるすべてのコマンドのリストです。どのチームがありますか?



  • bundle -モジュールとプロジェクトの依存関係を1つのファイルに収集します
  • cache -依存関係をキャッシュします
  • completions -シェルリフィルを生成します
  • doc -モジュールのドキュメントを表示します
  • eval -たとえば、コードのブロックを計算するために使用されます deno eval "console.log(1 + 2)"
  • fmt-組み込みのコードフォーマッタ(goFmtGoなど)
  • help -補助コマンドのリストを表示します
  • info -キャッシュまたはファイルに関する情報を表示します
  • install -スクリプトを実行可能として設定します
  • repl -読み取り-計算-出力サイクル(デフォルト)
  • run -モジュールの指定された名前またはURLでプログラムを実行します
  • test -テストを実行します
  • types -TypeScript機能のリストを表示します
  • upgrade -Denoを最新バージョンに更新します


deno <subcommand> helpたとえば、を 実行して特定のコマンドに関する情報を取得できますdeno run --help



コマンドdeno使用して、読み取り-評価-出力ループを開始できます。







これは、開始と同じdeno replです。



通常deno、TypeScriptファイルに含まれるDenoアプリケーションを実行するために使用されます。



TypeScriptファイル(.ts)とJavaScriptファイル(.js)の両方を実行できます。



TypeScriptを初めて使用する場合でも、心配する必要はありません。DenoはTypeScriptで記述されていますが、クライアントアプリケーションはJavaScriptで記述できます。



Denoの最初のアプリ



最初のアプリケーションを作成しましょう。



これを行うには、コードを記述する必要はありません。URLを使用してターミナルで実行します。



Denoはプログラムをダウンロードし、コンパイルして実行します。







もちろん、インターネットからランダムなコードを実行することはお勧めしません。この場合、Denoの公式Webサイトから起動します。さらに、Denoには、プログラムが明示的に許可していないことを実行できないようにするサンドボックスがあります。



このプログラムは非常にシンプルで、呼び出しconsole.log()です:



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


https://deno.land/std/examples/welcome.tsをブラウザで 開くと、次のように表示されます。







奇妙ですね。TypeScriptファイルが表示されることを期待していましたが、代わりにWebページを取得しました。重要なのは、Deno Webサイトサーバーは、ユーザーがブラウザーを使用していることを認識し、よりユーザーフレンドリーなページを提供するということです。たとえば、



を使用して同じURLをロードし、代わりにwget取得しtext/plainますtext/html







キャッシュのおかげでプログラムを再起動すると、再起動は必要ありません







フラグを使用して--reload強制再起動を実行できます:で







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のウェブサイトに他の例があります



この記事の執筆時点では、指定されたリポジトリに次のものがあります。



  • cat.ts -引数として渡されたファイルの内容を表示します
  • catj.ts-同じことをしますcat.tsが、最初にファイルの内容でいくつかの操作を実行します
  • chat/ -チャットの実装
  • colors.ts -モジュールを使用したテキストのスタイル設定の例
  • curl.ts-curl引数として渡されたURLのコンテンツを出力する単純な実装
  • echo_server.ts -TCPエコーサーバー
  • gist.ts -gist.github.comにファイルを配置するためのプログラム
  • test.ts -テストプログラム
  • welcome.ts -私たちが立ち上げたプログラム
  • xeval.ts-任意の標準データソースから取得したTypeScriptを実行できます。deno xeval公式チームのリストから削除されました


Denoの最初の本物のアプリ



コードを書いてみましょう。



私たちが最初に立ち上げたアプリdeno run https://deno.land/std/examples/welcome.tsはすでに作成されているため、Denoについて新しいことは何も学びません。



DenoのWebサイトに投稿されている標準的な例から始めましょう。



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


ここではserve、モジュールから関数インポートしていますhttp/server見る?インストールする必要はなく、ノードモジュールのようにコンピューターに保存されません。これが、Denoをすばやくインストールする理由の1つです。



助けhttps://deno.land/std/http/server.ts借りて、モジュールの最新バージョンをインポートします。特定のバージョンは、以下を使用してインポートできます@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' })
}


関数でawaitコードをラップせず にキーワード使用していることに注意してくださいasync



プログラムをローカルで実行してみましょう。私はVSコードを使用していますが、どのエディターでも使用できます。



justjavacから拡張機能をインストールすることをお勧めします(同様の名前の







拡張機能がありますが、非推奨であり、将来的になくなる可能性があります):拡張機能は、Denoアプリケーションの作成に役立ついくつかのユーティリティを提供します。



ファイルapp.ts作成して、コードをそのファイルに貼り付けましょう







実行deno run app.ts







Denoは、プログラムに必要なすべての依存関係をロードしますが、最初にファイルにインポートする依存関係をロードします。https://deno.land/std/http/server.ts



ファイルには、独自のいくつかの依存関係があります。



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


これらの依存関係は自動的にインポートされます。



最後に、問題があります。







何が起こっているのでしょうか。許可拒否エラーが発生しました。



サンドボックスについて話しましょう。



サンドボックス



先に述べたように、Denoには、プログラムが許可を得ていないことを実行できないようにするサンドボックスがあります。



これは何を意味するのでしょうか?



Ryanが講演で述べているように、JavaScriptプログラムをブラウザーの外部で実行したいが、プログラムがシステム上のすべてにアクセスできるようにしたくない場合があります。または、ネットワークを使用して外の世界になると。



Node.jsアプリケーションがシステムからSSHキーまたはその他の情報を取得し、それをサーバーに送信することを妨げるものは何もありません。これが、通常、信頼できるソースからのノードパッケージのみをインストールする理由です。しかし、使用しているプロジェクトの1つがハッキングされているかどうかをどうやって知ることができますか?



Denoは、ブラウザで使用される許可システムを模倣しています。ブラウザで実行されているJavaScriptコードは、明示的に許可しない限り、システムで何も実行できません。



Denoに戻ると、プログラムにネットワークアクセスが必要な場合は、その許可を与える必要があります。



これはフラグを使用して行われ--allow-netます:



deno run --allow-net app.ts






サーバーは現在、ポート8000​​で実行されています。







その他のフラグ:



  • --allow-env -環境変数へのアクセスを許可します
  • --allow-hrtime -高解像度の測定が可能
  • --allow-net=<allow-net> -ネットワークへのアクセスを許可します
  • --allow-plugin -プラグインのロードを許可します
  • --allow-read=<allow-read> -ファイルの読み取りを許可します
  • --allow-run -サブプロセスを開始できます
  • --allow-write=<allow-write> -ファイルの書き込みを許可します
  • --allow-all-すべての権限を付与します(同様-A


の権限netreadおよびwrite部分的な場合があります。たとえば、特定のディレクトリにある読み取り専用ファイルを許可できます--allow-read=/dev



コードのフォーマット



Goについて私が気に入っていることの1つは、コマンドgofmtです。すべてのGoコードは同じように見えます。誰もがそれを使用していgofmtます。



JavaScript開発者は通常、Prettierを使用しますがdeno fmt、実際には、カットの下でも使用します。



このような不適切なフォーマットのファイルがあるとします。







開始するdeno fmt app.tsと、セミコロンが欠落した状態で自動フォーマットが実行されます







標準ライブラリ



プロジェクトの時代にもかかわらず、デノの標準ライブラリは非常に広範です。



これには次のものが含まれます。



  • archieve -アーカイブ用のユーティリティ
  • async -非同期コードを操作するためのユーティリティ
  • bytes -バイトを分割するためのヘルパー関数
  • datetime -日付/時刻の解析
  • encoding -さまざまな形式でのエンコード/デコード
  • flags -コマンドラインフラグの解析
  • fmt -形成と表示
  • fs -ファイルシステムを操作するためのアプリケーションインターフェイス
  • hash -暗号化ライブラリ
  • http -HTTPサーバー
  • io -入力/出力操作のライブラリ
  • log -ロギング用のユーティリティ
  • mime -混合データのサポート
  • node -ノードとの下位互換性レイヤー
  • path -パスを操作する
  • ws -Webソケット


もう1つの例



別の公式の例を見てみましょう- 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()
}


コマンドラインを使用して渡された引数を含む 変数である変数にfilenamesコンテンツを割り当てますDeno.args



それらを繰り返し処理し、それぞれについて、最初にそれら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


パーミッションエラーが発生します:







Denoはデフォルトでシステムにアクセスできません。彼にそのような許可を与えましょう--allow-read



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






Express / Hapi / Koa / * Denoには存在しますか?



はい。次のプロジェクトを見てください。





例:Oakを使用してRESTAPIを作成する



Oakを使用してRESTAPIを作成します。Oakは、NOde.jsで人気のあるミドルウェアであるKoaに触発されており、同様の構文を持っているという点で興味深いものです。



APIは非常にシンプルになります。



私たちのサーバーは、犬のリスト、名前、年齢をメモリに保存します。



次の機能を取得したいと考えています。



  • リストに新しい犬を追加する
  • すべての犬のリストを取得します
  • 特定の犬に関する情報を取得する
  • リストから犬を削除します
  • 犬の年齢を更新する


Typescriptでコードを記述しますが、JavaScriptでコードを記述できます。データタイプを指定しないでください。



ファイルを作成しますapp.ts



さんがにオブジェクトをインポートすることから始めましょうApplicationRouterからOak



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は依存関係をダウンロードします:







そしてポート4000でリッスンを開始します。



再起動時に、キャッシュのおかげでインストール手順がスキップされ







ます犬のインターフェースを定義しdog、オブジェクトを含む配列定義しますDog



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




これらのルートを1つずつ実装してみましょう。すべての犬のリストを返す、



から始めましょうGET /dogs



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 dog: Dog = await body.value
    dogs.push(dog)

    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
}






完全なアプリケーションコード:



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


清聴ありがとうございました。