HonoとZodとCloudflare Workersで作る3分QRコードAPIクッキング

2022/12/17に公開2

この記事は呉高専 Advent Calendar 2022 16日目の記事になります。

こんにちは、呉高専在学中のWebフロントエンドエンジニアのkobakazu0429です。

本日の料理

「QRコードAPI、季節のHonoにZodを添えて、お皿にはCloudflare Workers」です。

HonoとCloudflare Workersとは?

Honoの作者のyusukebeさんが書かれている記事を読んでおけばOKです。

https://zenn.dev/yusukebe/articles/0c7fed0949e6f7

Zodとは?

TypeScript向けのスキーマ、バリデーションライブラリです。

こちらはyoshihiro nakamuraさんの記事を読んでおけばOKです。

https://zenn.dev/ynakamura/articles/65d58863563fbc

レシピ

メインのコードは次の通りです。

https://github.com/kobakazu0429/qr-api-worker/blob/master/src/routes/api/v1.ts

https://<qr-image>.worker.dev/api/v1/?text=test&type=pngのように書くことでQRコードを作成し、画像を返してくれます。

今回のミソは↓です。

https://github.com/kobakazu0429/qr-api-worker/blob/master/src/routes/api/v1.ts#L7-L14

デフォルト値を指定することでサクッと叩くことができるようになっています。

Scrapbox対応

Scrapboxに限った話ではないですが、URLのファイル名などを見て画像かどうか判断する場合のために、

https://<qr-image>.worker.dev/api/v1/filename.png?text=test&type=png

なども受け付けるようにしています。

Honoのvalidationについて

詳しくはリリースノートなどを見ていただきたいのですが、先週のアップデート(v2.6.0)にて組み込みのvalidation機能に加え、サードパーティーのvalidationも可能になったようです。

https://github.com/honojs/hono/releases/tag/v2.6.0

今回のAPIを作るときにはなかった機能なので上記のコードではhandler内でparseしています。

まとめ

Honoが本当に素晴らしいので(多分)3分クッキングで作れます。

ちなみにQRコードを作れるAPIなんてよくあるじゃんという声もあるかなと思うのですが、開発元が不明であったり、いつ使えなくなるかわからない状況が多いように感じています。

拙著にて恐縮ですが、下記のような場合では安定性が高く開発元が明確であることが望ましいことから、作成した次第です。

https://zenn.dev/kobakazu0429/articles/7427b2e8334f1a

また個人でQRコードAPIを持っておけば、個人開発などでも気軽に使えるのでおすすめです!


「QRコード」は株式会社デンソーウェーブの登録商標です。

Discussion

yusukebeyusukebe

こんちわ。Hono、使ってくれてありがとうございます!!
なんか理想的な使われ方で感動しております。

ZodによるValidatorについてですが、ハンドラの中でやるの、ぜんぜんOKだと思います。
で、ここからは余談なんですが、将来的にミドルウェアに組み込んでやるといいことがあります。

たとえば、こんなミドルウェアをつくります。
これはそのうち@honojs/zodとかで提供するかもしれません。

const zValidator = <T extends ZodType>(schema: T): Handler<z.infer<T>> => {
  return async (c, next) => {
    const parsed = schema.safeParse(c.req.query())
    if (!parsed.success) {
      return c.text('Invalid!', 400)
    }
    c.req.valid(parsed.data)
    await next()
  }
}

それをハンドラに適応します。見慣れない「build()」というメソッドがあります。

const getRoute = apiV1
  .get('/*', zValidator(schema), (c) => {
    const { text, options } = c.req.valid()
    const code = imageSync(text, options)
    c.header('Content-Type', MIME_TYPE[options.type])
    c.status(201)
    return c.body(code)
  })
  .build()

typeをexportします。

type AppRoute = typeof getRoute

それをfetch用のクライントで読み込むと...

SS

型ついてる!!!

ってなります。今回アプリは、HTTPクライアントから叩かれる想定じゃないので、
あまりうまみがないかもですが、フロントエンドのUIからのアクセスだと
便利じゃないかな〜〜〜って妄想しつつプロトタイプを作ってます。

詳しくはこちらのIssueにしてるので、興味があればみてみてこのIssueでもこちらのコメント欄でもいいので
コメントください!

https://github.com/honojs/hono/issues/727

kobakazu0429kobakazu0429

うぉ〜!素晴らしいです...!
クライアントからタイプセーフに叩けるのは便利ですね!(しかも手元でQRのAPI用に書いてくださっている...🙇)

Issue拝見させていただきます!!