DenoとCanvasを使ってGitHubのアクティビティ(草)の画像を生成するプロジェクトを作った
swfz/deno-kusa-image: GitHub Contribution Image in deno
こんな感じでGitHubの草を画像化したレスポンスを用意するくん(パラメータとかは執筆時のものなので今後変わる可能性はある)
https://kusa-image.deno.dev/?user=swfz
user
を指定するだけ
やっていること
- Deno.serveでサーバを立てる
- GitHubのAPIをたたく
- Canvasでレンダリングし、画像レスポンスにする
server
Deno.serve
を使った
Deno.serve | Runtime APIs | Deno
ドキュメントみながら書くだけでOK
GitHubのAPI
GraphQLのAPIでContribution情報が取得できるのでここから取得している
ドキュメントは下記参照すれば分かる
GitHub GraphQL API に関するドキュメント - GitHub Docs
あとはExplorerで実行しながらみてみると良い
次のようなクエリで
user名を引数で渡すとそのユーザーに関するContributionのデータを取得できる
query($userName:String!) { user(login: $userName){ contributionsCollection { contributionCalendar { totalContributions weeks { contributionDays { color contributionCount contributionLevel date } } } } } }
コードに落とし込むと次のような感じ
const token = Deno.env.get("GH_READ_USER_TOKEN"); const query = ` query($user:String!) { user(login: $user){ contributionsCollection { contributionCalendar { totalContributions weeks { contributionDays { color contributionCount contributionLevel date } } } } } } `; const variables = { user }; const json = { query, variables }; const url = "https://api.github.com/graphql"; const res = await fetch(url, { method: "POST", headers: { Authorization: `Bearer ${token}` }, body: JSON.stringify(json), }); res.json();
Canvas
Denoでcanvasを扱うためのライブラリ
https://deno.land/x/canvas@v1.4.1deno.land
使い方は通常のCanvasの使い方と同様、一部対応してないメソッドなどもあるが基本的なものは使えるはず
GitHubのAPIの情報をもとにレンダリングするだけ
コードは少し長くなってしまうので載せないが下記にある
deno-kusa-image/renderCanvas.ts at main · swfz/deno-kusa-image
最後にcanvas.toBuffer()
でレスポンスに指定するだけで画像としてレスポンスを返してくれる
Canvasで何かしらレンダリングして画像としてレスポンスを返すサンプル
- server.ts
import { createCanvas } from "https://deno.land/x/canvas/mod.ts"; const port = 8080; const handler = (request: Request): Response => { const canvas = createCanvas(200, 200); const ctx = canvas.getContext("2d"); ctx.fillStyle = "red"; ctx.fillRect(10, 10, 200 - 20, 200 - 20); const headers = new Headers(); headers.set("content-type", "image/png"); return new Response(canvas.toBuffer(), {headers: headers, status: 200 }); }; console.log(`HTTP webserver running. Access it at: http://localhost:8080/`); Deno.serve({ port }, handler);
これだけで画像としてのレスポンスを返せる
開発とデプロイ
- ローカルでの開発(run)
deno run --allow-net --allow-env server.ts
APIへの接続と環境変数にGitHubのGraphQLAPIへのアクセスキーが必要なため--allow-net
,allow-env
を指定
- デプロイ(deployctl)
deployは事前にDenoアカウントを作っておく必要はあるがめちゃくちゃ簡単だった
deployctl deploy --project=kusa-image --prod server.ts
--project
は必須、一意の文字列にする必要がある
--prod
をつけないとプレビュー用にデプロイできるのでそこで確認してproductionデプロイといった手順を踏むこともできる
まとめと感想
- DenoとCanvasを使ってGitHubのアクティビティを画像化するサーバを作った
- 画像なのでOGPに使うことができる
- この組み合わせに限らず、パラメータをもとに動的に画像生成するのは色々準備が必要でたいへんなイメージだったが、この組み合わせだとさくっとできた
- 色々できそうだなと感じたので他にも作ってみたい
- ContributionAPIがアクティビティに関する情報をほとんど持っているので、取得したレスポンスをそのまま使ってCanvasのレンダリングするだけでOKで楽
- RGBまで返ってくるのでカスタマイズしなくてよいのなら色指定も不要だった