はじめに
この記事は 某社の Advent Calendar 10日目の記事です。
こんにちは。 mirko です。
この記事で書くこと
この記事では、 Deno と oak で任意のレスポンスヘッダでレスポンスを返すサーバーを立てる方法について解説します。
Deno と oak (と CORS 対応のために必要になる cors ライブラリ) のバージョンは以下で確認しています。
名前 | バージョン |
---|---|
Deno | 1.16.0 |
oak | 10.0.0 |
cors | 1.2.2 |
なぜ作ったか
ある API エンドポイントを叩いた時に Content-Disposition
ヘッダに attachment; filename="filename.txt"
のように入れるのでそれをパースしてフロントエンドで指定した filename
でファイルダウンロードできるようにしておいてください、となったが、諸般の事情でバックエンドができる前にフロントエンドを着手したかったので。(また、代わりに使えそうなフリーのAPIがうまいこと見つけられなかったので)
実装
ts ファイルを書く
import { Application } from "https://deno.land/x/oak@v10.0.0/mod.ts";
import { oakCors } from 'https://deno.land/x/cors@v1.2.2/mod.ts';
const app = new Application();
app.use(oakCors());
app.use((ctx: any) => {
ctx.response.body = 'sample response body';
ctx.response.headers.set('Content-Type', 'text/plain');
ctx.response.headers.set('Access-Control-Expose-Headers', '*');
ctx.response.headers.set('Content-Disposition', 'attachment; filename="filename.txt"');
});
await app.listen({ port: 8000 });
実行する
deno run --allow-net server.ts
これだけ。
curl を叩くと、以下のようなレスポンスが得られます。
$ curl -v http://localhost:8000
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< access-control-allow-origin: *
< access-control-expose-headers: *
< content-disposition: attachment; filename="filename.txt"
< content-type: text/plain
< content-length: 20
< date: Fri, 03 Dec 2021 15:41:43 GMT
<
* Connection #0 to host localhost left intact
sample response body* Closing connection 0
解説
HTTP サーバーを立てる
// 基本的には oak のドキュメントを通りで恐縮です。
以下のように Application
class をインポートします。
import { Application } from "https://deno.land/x/oak@v10.0.0/mod.ts";
Application
class を初期化したら
const app = new Application();
.use()
でリクエストを指定しています。
app.use((ctx: any) => {
ctx.response.body = 'sample response body';
ctx.response.headers.set('Content-Type', 'text/plain');
ctx.response.headers.set('Access-Control-Expose-Headers', '*');
ctx.response.headers.set('Content-Disposition', 'attachment; filename="filename.txt"');
});
最後に listen するポートを指定します。
await app.listen({ port: 8000 });
今回は任意のレスポンスヘッダでレスポンスを返したかったので上記のように書いていますが、任意のレスポンスボディを返すのみでしたら、以下のコードだけでも動きます。
// https://deno.land/x/oak@v10.0.0 より引用
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use((ctx) => {
ctx.response.body = "Hello World!";
});
await app.listen({ port: 8000 });
CORS 対応をする
実は上記部分だけでも curl -v http://localhost:8000
で意図したレスポンスを得られますが、ローカル開発環境が localhost
ではない場合 CORS エラーとなります。
そのため、以下のように CORS 対応をしました。
cors
モジュールを import します。
import { oakCors } from 'https://deno.land/x/cors@v1.2.2/mod.ts';
公式の例 を参考に、今回は複雑な route も定義していないので、シンプルに oakCors
を有効化します。
app.use(oakCors());
これで CORS 対応は完了しました。はやい!
書いてみた感想
- めちゃくちゃサクっと書きたいものが書けた
- 環境構築に時間をかけず気持ちよく TypeScript が書けていい感じ
- 配布ライブラリに型が書いてあるのもサクっと書く助けになってくれた
これからも公私共に Deno を使っていきたいと思いました!