Vercel はもっと薄く使える
はじめに
Vercel Ship、アツい発表が続いていますね。
特に初日の Storage は、KV、Postgres、Blob と 3 つのプロダクトが公開され、「とりあえず何か試したい!」「今の構成のあのコンポーネントは Vercel で済ませられるようになりそう!」となった方も多いんじゃないでしょうか。
Vercel で何かしら関数を動かすとなった時に一番最初に思い付かれがちな選択肢は、とりあえず create-next-app
して pages/api/hello.ts
を作成して... というあれですが、Vercel を使ってみたい人(またはプロジェクト)のうち全員が React を使っているわけではありませんし、そもそもフロントエンド無しで完結するユースケースも多いはずです。
Vercel の Serverless Functions は(ご存知の方も多いと思いますが)実際には Framework agnostic なもので、もっと薄く、Node.js だけでも[1]使うことができます。
便利な反面、あまり一般的では無さそうなので、使い方を紹介します。
Demo Repository
こちらの README にもある程度書いています。
Serverless Functions
root に api
ディレクトリを作成し、以下のようにハンドラを default export するファイルを置くと、Serverless Functions として動作します。
デモ: https://vanilla-vercel-functions.vercel.app/api/hello
import type { VercelRequest, VercelResponse } from '@vercel/node';
export default function handler(req: VercelRequest, res: VercelResponse) {
res.status(200).json({
message: 'Hello world',
cookies: req.cookies,
})
}
Edge Functions
以下のような config
オブジェクトを export
すると、Edge Functions として動作させることができます。
Edge Functions のランタイムは軽量で、Node.js ではないので様々な制約を受けますが、その分パフォーマンスや物理的距離によるレイテンシの低さで様々な使い所があります。
また、@vercel/edge という npm パッケージが公開されていて、リクエストの地理情報・IP アドレスの取得等は簡単に行うことができます。
デモ: https://vanilla-vercel-functions.vercel.app/api/edge
import { geolocation } from '@vercel/edge';
export const config = {
runtime: 'edge',
};
export default function handler(req: Request) {
const { city } = geolocation(req);
return new Response(`Hello, from ${city} I'm now an Edge Function!`);
}
ちなみに
Vercel KV
上記のような関数から、最近発表された Vercel KV などの Storage にもアクセスできます。
(確認してませんが Postgres や Edge Config、Blob も同様かと思います。)
例えば Node.js の場合、@vercel/kv というクライアントライブラリが公開されていますが、こちらがありがたいことにエッジランタイムで動作可能になっているので、Edge Functions でも使えます。
以下は来訪者カウンター実装の例です。
デモ: https://vanilla-vercel-functions.vercel.app/api/kv
こちらのデモは現在動作しません。
import type { RequestContext } from '@vercel/edge';
import kv from '@vercel/kv';
export const config = {
runtime: 'edge',
};
export default async function handler(_: Request, ctx: RequestContext) {
const currentCount = (await kv.get<number>('visitor-count')) ?? 0;
const incremented = currentCount + 1;
ctx.waitUntil(kv.set('visitor-count', incremented));
return new Response(`You're No. ${incremented} visitor!`);
}
express もデプロイできる
express のインターフェースは Serverless Functions に互換なので、イベントハンドラとしてそのまま利用できます。
デモ: https://vanilla-vercel-functions.vercel.app/api/express/posts/with-dynamic-param
import express, { Router } from 'express';
const app = express();
const router = Router();
router.get('/posts/:slug', (req, res) => {
res.json({
post: {
title: 'Test Post',
slug: req.params['slug'],
},
});
});
app.use('/api/express', router);
export default app;
(本当は Hono を使いたかったんですが、うまく動かせませんでした。分かる方いたら教えてください。)
🔥 Hono も使えた(追記 - 2023.05.05)
hono/nextjs で動かせるようでした!(動かなかったのはバージョンか書き方のミスだったかもしれません。)
hono だと組み込みの BASIC 認証ミドルウェアで、簡単に認証がかけられたりもしていて圧倒的に便利ですね。
また、エッジで動くようです。
デモ: https://vanilla-vercel-functions.vercel.app/api/hono/auth
ID: vercel
/ PW: hono
import { Hono } from 'hono'
import { basicAuth } from 'hono/basic-auth'
import { handle } from 'hono/nextjs'
export const config = {
runtime: 'edge',
}
const app = new Hono().basePath('/api/hono')
app.get(
'/auth',
basicAuth({
username: 'vercel',
password: 'hono',
}),
(c) => {
return c.text('Authorized!')
}
)
export default handle(app)
ご対応ありがとうございます!
Static Files
Vercel ならデフォルトで Static File Serving が有効なので、public
ディレクトリに置くだけで雑に配信できます。
Web サイトが必要なわけではなくても、画像などちょっとしたファイルを配信したいことは多いと思うので、ついでに活用しましょう。
デモ: https://vanilla-vercel-functions.vercel.app/author.jpg
まとめ
これでもう、API をデプロイしたいだけなのに npm i next
や npm i react
をして不思議な気持ちにならずにすみますね。
-
Node.js の他に公式で Go、Python、Ruby、非公式で Bash、Deno、PHP、Rust のランタイムがサポートされています。
https://vercel.com/docs/concepts/functions/serverless-functions/runtimes ↩︎
Discussion
Honoの作者です。Honoも動きました〜。以下のPRではミドルウェアを動くぞ!ってことで、ベーシック認証の例もいれてます。
ありがとうございます!記事加筆修正しました。