まえがき
最近私はツールを開発する環境として「Deno」が気に入っています。
シンプルで、軽くて、ランタイムAPIや標準ライブラリが充実していて、開発体験が良いと感じています。
私のところではDenoを本番で採用しようとすると諸々ハードルがありますが、ツールの開発であれば選択肢として大いにアリです。
この記事では、Deno/TypeScriptの概要と、サンプルとして「HTTPレスポンス(JSON)をCSVファイルに出力するツール」の開発手順を解説します。
私自身も初学者なので、間違い等があればコメントでご教示ください。
前提環境
Deno 1.20.5
Denoとは
概要
Wikipediaより引用:
Denoは、V8 JavaScriptエンジン及びRustプログラミング言語に基づいた、JavaScript及びTypeScriptのランタイム環境である。
Node.jsの作者であるライアン・ダールによって作成され、セキュリティと生産性に焦点を当てている。
ライアン・ダールが2018年に行った講演「Node.jsに関する10の反省点」で発表された。
主な特徴
TypeScriptを標準サポート
- トランスパイラを内蔵しており、Babelなどのトランスパイラ環境がなくても実行できます。
TypeScript Deep Dive 日本語版より引用:
TypeScriptはJavaScriptを拡張して作られたプログラミング言語です。
トレンドが示すとおり、TypeScriptはJavaScriptに代わって第一に選択される言語になりました。
TypeScriptが提供する静的型システムは、コードの保守性と可読性を大幅に向上させます。
またブラウザ等の互換性を心配することなく、モダンで便利なJavaScriptの機能を利用できます。
パッケージ(モジュール)管理の仕組みがシンプル
-
npm
,node_modules
,package.json
といったツールや設定ファイルがありません。 - 外部モジュールを使う場合は
import
にURLを渡すだけ。さらにrequire
も不要です。
import { format, parse } from "https://deno.land/std@0.138.0/datetime/mod.ts";
- ダウンロードは実行時に行われ、結果はキャッシュされます。
- すなわち、Denoはランタイム環境であるだけでなくパッケージ管理ツールの役割も持っています。
その他にも、素晴らしい特徴がいろいろあります。さらに詳しく知りたい方は文末のリンク集をご参照ください。
Denoのインストール
公式ドキュメントを参照するのが確実です。
Visual Studio Code (VSCode) の環境構築
テキストエディタでも開発は可能ですが、統合開発環境(IDE)の方が、コード補完や静的チェックが効きますので開発が捗ります。
Denoでは皆さんVSCodeを使っていらっしゃるようです。
以下の記事に素晴らしくまとまっています。
あれこれ調べるのがめんどくさかったら(笑)、
拡張機能「Deno for Visual Studio Code」をインストールして、
作業フォルダ配下に.vscode
フォルダを作成し、
以下のファイルを格納すれば、とりあえず開発を始められると思います。
{
"debug.javascript.unmapMissingSources": true,
"deno.enable": true,
"deno.lint": true,
"deno.unstable": true,
"deno.suggest.imports.hosts": {
"https://deno.land": true
}
}
VSCodeのデバッグ実行を使いたい場合はlaunch.json
も格納します。
launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Deno",
"type": "pwa-node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "deno",
"runtimeArgs": ["run", "--inspect-brk", "-A", "./app.ts"],
"attachSimplePort": 9229
}
]
}
※app.tsはアプリケーションのエントリーポイントとなるファイル名ですので、適宜書き変えてください。
「HTTPレスポンス(JSON)をCSVファイルに出力するツール」の開発
APIについて
APIキーもログインも不要で無料で使える天気予報API「Open-Meteo」を使ってみます。
(※商用利用はNGのようです。ライセンス要件をご確認ください。)
Open-Meteoはパラメータによって様々なデータを取得できますが、今回は「東京の1週間分の気温」をGETします。
URLは以下で、ブラウザでも試すことが出来ます。
https://api.open-meteo.com/v1/forecast?latitude=35.6785&longitude=139.6823&hourly=temperature_2m&timezone=Asia%2FTokyo
レスポンスJSONのサンプル
{
utc_offset_seconds: 0,
hourly: {
temperature_2m: [
20.5, 21, 21.3, 21.3, 21.6, 21.4, 19.8, 18.3, 17.6, 17,
16.7, 16.7, 16.5, 16.3, 16.1, 16.1, 16.1, 16, 15.9, 15.9,
15.5, 14.5, 14, 14.4, 15.3, 15.7, 15.3, 15, 15.1, 14.8,
14.2, 13.8, 13.4, 13, 12.7, 12.6, 12.5, 12.5, 12.4, 12.4,
12.4, 12.4, 12.3, 12.2, 12.1, 12.6, 14.1, 15.8, 17.6, 18.7,
20.6, 22, 22, 21.4, 20.9, 20, 19.1, 18.1, 17.3, 16.9,
16.5, 16.2, 16, 16, 16, 15.9, 15.9, 15.9, 15.9, 15.9,
16, 16.3, 16.3, 16.8, 17.4, 18.1, 18.3, 18.4, 18.3, 18.2,
18, 17.8, 17.7, 17.6, 17.5, 17.4, 17.3, 17.1, 17, 16.9,
16.8, 16.7, 16.7, 16.8, 17.3, 17.9, 18.8, 19.6, 20.5, 21.5,
... 68 more items
],
time: [
"2022-05-08T00:00", "2022-05-08T01:00", "2022-05-08T02:00",
"2022-05-08T03:00", "2022-05-08T04:00", "2022-05-08T05:00",
"2022-05-08T06:00", "2022-05-08T07:00", "2022-05-08T08:00",
"2022-05-08T09:00", "2022-05-08T10:00", "2022-05-08T11:00",
"2022-05-08T12:00", "2022-05-08T13:00", "2022-05-08T14:00",
"2022-05-08T15:00", "2022-05-08T16:00", "2022-05-08T17:00",
"2022-05-08T18:00", "2022-05-08T19:00", "2022-05-08T20:00",
"2022-05-08T21:00", "2022-05-08T22:00", "2022-05-08T23:00",
"2022-05-09T00:00", "2022-05-09T01:00", "2022-05-09T02:00",
"2022-05-09T03:00", "2022-05-09T04:00", "2022-05-09T05:00",
"2022-05-09T06:00", "2022-05-09T07:00", "2022-05-09T08:00",
"2022-05-09T09:00", "2022-05-09T10:00", "2022-05-09T11:00",
"2022-05-09T12:00", "2022-05-09T13:00", "2022-05-09T14:00",
"2022-05-09T15:00", "2022-05-09T16:00", "2022-05-09T17:00",
"2022-05-09T18:00", "2022-05-09T19:00", "2022-05-09T20:00",
"2022-05-09T21:00", "2022-05-09T22:00", "2022-05-09T23:00",
"2022-05-10T00:00", "2022-05-10T01:00", "2022-05-10T02:00",
"2022-05-10T03:00", "2022-05-10T04:00", "2022-05-10T05:00",
"2022-05-10T06:00", "2022-05-10T07:00", "2022-05-10T08:00",
"2022-05-10T09:00", "2022-05-10T10:00", "2022-05-10T11:00",
"2022-05-10T12:00", "2022-05-10T13:00", "2022-05-10T14:00",
"2022-05-10T15:00", "2022-05-10T16:00", "2022-05-10T17:00",
"2022-05-10T18:00", "2022-05-10T19:00", "2022-05-10T20:00",
"2022-05-10T21:00", "2022-05-10T22:00", "2022-05-10T23:00",
"2022-05-11T00:00", "2022-05-11T01:00", "2022-05-11T02:00",
"2022-05-11T03:00", "2022-05-11T04:00", "2022-05-11T05:00",
"2022-05-11T06:00", "2022-05-11T07:00", "2022-05-11T08:00",
"2022-05-11T09:00", "2022-05-11T10:00", "2022-05-11T11:00",
"2022-05-11T12:00", "2022-05-11T13:00", "2022-05-11T14:00",
"2022-05-11T15:00", "2022-05-11T16:00", "2022-05-11T17:00",
"2022-05-11T18:00", "2022-05-11T19:00", "2022-05-11T20:00",
"2022-05-11T21:00", "2022-05-11T22:00", "2022-05-11T23:00",
"2022-05-12T00:00", "2022-05-12T01:00", "2022-05-12T02:00",
"2022-05-12T03:00",
... 68 more items
]
},
hourly_units: { temperature_2m: "°C", time: "iso8601" },
longitude: 139.625,
generationtime_ms: 2.048015594482422,
elevation: 20.84375,
latitude: 35.625
}
CSV出力結果のサンプル
2022/05/08 00:00,16.8
2022/05/08 01:00,16.4
2022/05/08 02:00,16.2
2022/05/08 03:00,16.5
2022/05/08 04:00,16.4
(以下略)
コード
import { format, parse } from "https://deno.land/std@0.138.0/datetime/mod.ts";
let output = "";
let temperatureList: number[] = [];
let dateTimeList: string[] = []; // e.g."2022-05-08T21:00"
// GETとparse
try {
// 東京の1週間分の気温をGET
const response = await fetch(
"https://api.open-meteo.com/v1/forecast?latitude=35.6785&longitude=139.6823&hourly=temperature_2m&timezone=Asia%2FTokyo",
);
const responseJson = await response.json();
console.log(responseJson);
temperatureList = responseJson["hourly"]["temperature_2m"] as number[];
dateTimeList = responseJson["hourly"]["time"] as string[];
} catch (e) {
console.log(`API error: ${e.message}`);
Deno.exit();
}
// CSV出力用文字列に整形
temperatureList.forEach((temperature, i) => {
// 2件め以降の場合は改行を挿入
if (i > 0) {
output += "\n";
}
// 日時フォーマット
const outputDateTime = format(
parse(dateTimeList[i], "yyyy-MM-dd'T'HH:mm"),
"yyyy/MM/dd HH:mm",
);
// CSV出力用文字列に追加
output += `${outputDateTime},${temperature}`;
});
// CSV書き出し
try {
Deno.writeTextFileSync("./temperature.csv", output);
console.log(`Written to ./temperature.csv`);
} catch (e) {
console.log(`Output error: ${e.message}`);
Deno.exit();
}
実行
Denoのセキュリティ機構として、ネットワークを許可するための--allow-net
と、ファイル書き込みを許可するための--allow-write
オプションを付けて実行します。
$ deno run --allow-net --allow-write app.ts
コードのちょっとした解説
Denoの標準APIについて
Denoはブラウザのようにfetch
などのWeb標準APIを実装しています。
fetch_data
また、DenoのランタイムAPIは、テキストファイルの読み書きのために Deno.readTextFile
と Deno.writeTextFile
非同期関数を提供します。
同等の同期関数 Deno.readTextFileSync
と Deno.writeTextFileSync
もあります。
read_write_files
Denoの標準ライブラリについて
今回使用したdatetime
のような、Deno本体との連携が保証された標準ライブラリが提供されています。
標準ライブラリは、サードパーティ・ライブラリと同じくimport
して使用します。
また、import
する際には上のコードの/std@0.138.0
のようにバージョン番号をpathで指定します。
型について
なんと言っても、型を定義できることがTypeScriptの強みです。
型の間違いは、VSCodeでリアルタイムにチェックが働きます。
TypeScript Deep Dive 日本語版 > TypeScriptの型システム
さらに詳細な情報を得られるお勧めリンク集
Deno
TypeScript
あとがき
後続の「スタブ・サーバーを作ってみる編」もぜひ。。。