Workersで簡単にGoのHTTPサーバーを動かすためのライブラリを作ったので、紹介させていただきます。https://hello.syumai.workers.dev/?name=worldソースコードは、以下のような非常にシンプルな内容となっています。部分が、本ライブラリの提供している機能となります。handler変数は、通常のhttp.HandlerFuncと同じように実装しているだけです。Workersで動作するtinygoのサンプルを作ってみましたが、短時間で実用的なものを作るのは大変そうな感じがしました。Worker自体HTTPリクエストを処理するための機構ですし、サクッと実用的なアプリケーションを作るには、やはりhttp.Handlerをサポートするのが一番の早道だなと思ったのでこの実装方針にしました。あとは、WebAssemblyとJavaScriptの知識が要求される感じがあり、Goプログラマにとっては少しハードルが高いかもしれないと思ったので、なるべくJavaScript側の世界を意識しないで使えるライブラリが欲しいと思っていました。WorkersのRustバインディングのworkers-rsがうまくやっているので意識しつつ実装しています。渡すだけで終わりです。渡して呼び出してもOKです。})workers.Serve(nil)}実際に動かすには、WebAssemblyをロードするJavaScriptのコード等も必要になります。Workersのアプリケーションを作るためのテンプレートリポジトリを用意しているので、簡単に始めたい方はこちらをご利用ください。https://github.com/syumai/worker-template-tinygoライブラリの実装について実装は単純で、JavaScript側で受け取ったRequestオブジェクトをGoに渡すGo側でResponseオブジェクトを組み立ててJavaScript側に渡すと言う形式になっています。eventをハンドリングして、eventに付与されたRequestオブジェクトを処理し、Responseオブジェクトを返すと言う構造になっています。このとき問題になるのは、上記で示した内容から推測できる通り、JavaScriptとGo間での値の変換です。これは基本的には頑張るしかないので、値を変換するコードを大量に書いています。あとは、方針として、出来る限りデータをメモリ上に持たないようにする形で進めているので、JavaScriptのReadableStreamとGoのio.Readerを相互に変換するような実装が含まれています。言う関数を登録するようにしました。https://github.com/syumai/workers/blob/v0.2.1/handler.go#L13-L33JavaScript側から、この関数に対する呼び出しを行う箇所が、リクエストの処理開始地点となります。https://github.com/syumai/workers/blob/v0.2.1/examples/simple-json-server/worker.mjs#L15ストリームの変換ストリームの変換は、deno_stdのコードを参考にしました。Streamとの相互変換が必要なシーンが増えていました。言うファイルが作られていたのですが、この実装をほとんど移植するだけで完了しました。言え、syscall/jsでラップする必要があり、Promiseの扱いなどはやや面倒でした。Streamの変換処理の実装はこの辺りのコードで行っています。ところどころで、Go側からJSのPromiseをawaitするような処理が入っていたりします。チャネルを使ってPromiseの非同期処理の結果を待ち受ける実装になっていて、streamの処理以外でも必要になったのでユーティリティ関数として切り出しています。https://github.com/syumai/workers/blob/v0.2.1/jsutil.go#L39-L62ResponseWriterのReadableStreamへの変換これが地味に迷ったポイントだったのですが、Goのレスポンス形式は、ResponseWriterへの書き込み処理JS側のレスポンス形式は、ReadableStreamからの読み込み処理と言うことで、レスポンスの形式として書き込みと読み込みが逆転していました。問題を解決することに気付いてからの実装はすぐでした。https://twitter.com/__syumai/status/1526456929174048768?s=20&t=qoY_AS-0dOaSC4zXKhdBKwresponseWriterの実体に、io.Pipeから入手したreaderとwriterの両方を持たせ、Go側からはこのwriterへの書き込みを行い、https://github.com/syumai/workers/blob/v0.2.1/handler.go#L45JS側ではreaderからの読み込みを行うようにしました。https://github.com/syumai/workers/blob/v0.2.1/response.go#L28これで、Go側とJS側でレスポンスをストリーム処理することに成功しました。通常のGoでも動作することを確認できましたが、圧縮後のサイズが1MB以内でないといけない制約があるため、バイナリサイズが大きくなる通常のGoではpublishに成功しませんでした。実はtinygoでもギリギリで、依存ライブラリを増やすと簡単に越えます。依存を増やさずに、質素なアプリケーションを作っていく必要はありそうです。tinygoで困ったことはないか?tinygoと言う制約による悩みは結構多かったです。encoding/jsonが動きません。これはtinygoのreflectの実装が完全でないためで、代替のライブラリを探す必要があります。(takasagoさんにツイートで代替をいくつか教えていただきました)https://twitter.com/sago35tk/status/1526538044073193472?s=20&t=qoY_AS-0dOaSC4zXKhdBKw下記に、easyjsonを使ったサンプルを示しますが、構造体の定義を変更する度にコード生成をする必要があるので少々手間です。言え、ちょっとした用途なら全然使えそうな感じはしました。うまく動きませんでした(自分のやり方が悪いのか...?)。ベーシック認証をかけたプロキシサーバーを実装してみようと思ったのですが、外部にHTTPリクエストを送れなかったので断念しました。これは制約としてかなりキツいです。ベーシック認証が動作するだけのWorkerのサンプルは出来ましたが、あんまり実用性は無いような感じがします。listの全てを呼べます。オプションはまだほとんど対応していません。どれくらい動くかについては、実際に動作するサンプルを2つ用意しているので、こちらを見ていただくのが早いです。画像をR2から取得して返すだけの実装を行なっています。指定する必要はありますが、Goのみで実装出来ていることが確認いただけると思います。https://github.com/syumai/workers/blob/v0.2.1/examples/r2-image-viewer/main.go#L13-L14R2ObjectのBodyは、io.Readerを実装しているので、http.ResponseWriterにio.Copyすることが出来ます。した部分で、ややGoらしさを意識した実装となっています。deleteを行う実装が含まれています。https://github.com/syumai/workers/tree/v0.2.1/examples/r2-image-serverこちらはWeb上のデモは用意していませんが、お手元で簡単に確認いただけますので、ぜひ動かしてみてください。putの処理は、ReadableStreamの実装ではPromiseが永遠に解決されない状況に陥ってしまい、うまく動かせなかったため、現状メモリに全データをロードする実装になっています。こちらは早く直したいですが、かなりの格闘の末に失敗したので、ちょっと期間を置いてからチャレンジしようと思っています。testは?全然書けてません。syscall/jsが絡む処理のtestは結構面倒で、後回しにしていたら進捗ゼロになってしまいました...。以前DenoとGoのioインタフェースを相互変換するpackageを作った時は、GoのコードをWasmにコンパイルして、JS側でtestを実行するような形で書いていたので、このような雰囲気で進めようかなと思っています。https://github.com/syumai/denoio/tree/99abe35fbe76d8f6313d3bbed61a543b89d7830c/testおわりに以上、まだまだ開発中のライブラリではありますが、試しに遊んでみてください!何か作ってみた方がいらっしゃったら、ここのコメントやTwitterで教えていただけると嬉しいです!ぜひよろしくお願いします。JavaScriptまわりのプログラマですバッジを贈って著者を応援しようバッジを受け取った著者にはZennから現金やAmazonギフト券が還元されます。どれくらい使えるのか?testは?おわりにZennエンジニアのための情報共有コミュニティAboutZennについて運営会社お知らせ・リリースGuides使い方Publicationよくある質問LinksTwitterGitHubメディアキットLegal利用規約プライバシーポリシ。