たった数行で Python と JavaScript の Workers が直結!
やっほー、今日もしぃちゃんだよ!今日は Cloudflare Changelog から、開発者的にニヤッとしちゃうニュースだよ!
Cloudflare Changelogなにが発表されたの?
Cloudflare の Changelog によると、Workers RPC が Python の Worker と JavaScript の Worker のあいだでも使えるようになったよ。Service binding を通じて実現されていて、追加の依存関係やスキーマ定義、シリアライズ用のコードは一切いらないの。呼び出しはふつうの関数呼び出しと同じように振る舞って、例外(エラー)もちゃんと呼び出し元まで伝わるんだって。
今までどうだったの?
Workers RPC 自体はもともと同じ言語の Worker 同士でしか使えなかったの。Python の Worker と JavaScript の Worker を連携させたいときは、HTTP 経由で fetch したり、自分でシリアライズ形式を決めたりする必要があって、地味に手間がかかっていたんだよね。
これで何が変わるの?
これからは、Service binding さえ設定すれば、Python の Worker から JavaScript の Worker のメソッドを直接呼んだり、その逆をしたりできるようになるよ。パラメータや戻り値には structured cloneable な型がそのまま使えて、言語間の型変換は Pyodide の Foreign Function Interface(FFI)が自動でやってくれるの。
深く潜ってみよう
Python から TypeScript の Worker を呼ぶ例はこんな感じだよ。まず TypeScript 側で WorkerEntrypoint を継承したメソッドを用意するの。
import { WorkerEntrypoint } from "cloudflare:workers";
export class RpcService extends WorkerEntrypoint {
async add(a: number, b: number): Promise<number> {
return a + b;
}
}
Python の Worker からは、Service binding 経由でこんなふうに呼び出せるよ。
from workers import Response, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
rpc = self.env.RPC
result = await rpc.add(42, 144)
return Response.json({"result": result})
Python 側の Wrangler 設定はこう書くの。
[[services]]
binding = "RPC"
service = "ts-rpc-server"
entrypoint = "RpcService"
逆に JavaScript から Python の Worker を呼ぶこともできるよ。たとえば Python 側で Pygments を使ったシンタックスハイライト用のメソッドを用意しておくと、
from workers import WorkerEntrypoint
class Default(WorkerEntrypoint):
async def highlight_code(self, code: str, language: str) -> dict:
from pygments.formatters import HtmlFormatter
from pygments import highlight
from pygments.lexers import get_lexer_by_name
lexer = get_lexer_by_name(language, stripall=True)
formatter = HtmlFormatter(linenos=True, cssclass="highlight", style="monokai")
highlighted_html = highlight(code, lexer, formatter)
css = formatter.get_style_defs(".highlight")
return {"html": highlighted_html, "css": css}
JavaScript の Worker からは、こんなふうにそのまま呼べちゃうんだよ。
export default {
async fetch(request, env) {
const rpc = env.PYTHON_RPC;
const result = await rpc.highlight_code("print(42)", "python");
return Response.json(result);
},
};
JavaScript 側の Wrangler 設定はこれだけ。
[[services]]
binding = "PYTHON_RPC"
service = "py-rpc-server"
まとめ
- Workers RPC が Python と JavaScript の Worker のあいだでも使えるようになった
- Service binding だけで、API やスキーマ、シリアライズのコードなしにメソッドを直接呼び合える
- structured cloneable な型を使えて、型変換は Pyodide の FFI が自動でやってくれる
- 例外は呼び出し元にそのまま伝わる
Python のライブラリ資産を JavaScript から使いたい人や、逆に JS のエコシステムを Python の Worker から呼びたい人には、コピペしてすぐ試せる嬉しいアップデートだよ!