はじめに
データベースのトランザクションとリアルタイム性を維持するため、Convexのquery
関数とmutation
関数は、外部へのfetch
(データ取得)呼び出しができません。しかし、実際のアプリケーションでは外部サービスと通信する必要があるため、Convexはaction
関数を提供しています。action
関数を使うと、同期エンジンが外部世界にアクセスできるようになり、その結果をミューテーション関数を通じてデータベースに書き戻すことができます。
本チュートリアルでは、このaction
関数を使って、チャットアプリからWikipedia APIを呼び出し、トピックの要約を取得する機能を実装します。
実装
- アクション関数
getWikipediaSummary
- この関数を公開APIとしないようにするため、
internalAction
を使用。この関数は、指定されたトピックでWikipediaのAPIに単純なfetch
を行う。 - ctx.schedulerで、summaryをchatのsendMessageでチャットに送信する。
- この関数を公開APIとしないようにするため、
- ヘルパーTypeScript関数
getSummaryFromJSON
- JSONレスポンスから要約テキストを抜き出す。
- sendMessage関数の変更
- /wikiで始まる場合、直後のスペース後の文字列をtopicとする
- ctx.schedulerで、ミューテーション成功時に、getWikipediaSummaryアクションを非同期に呼び出すように設定する
import { query, mutation, internalAction } from "./_generated/server";
import { v } from "convex/values";
export const sendMessage = mutation({
args: {
user: v.string(),
body: v.string(),
},
handler: async (ctx, args) => {
console.log("This TypeScript function is running on the server.");
await ctx.db.insert("messages", {
user: args.user,
body: args.body,
});
// ADD HERE 4 !!!
if (args.body.startsWith("/wiki")) {
// Get the string after the first space
const topic = args.body.slice(args.body.indexOf(" ") + 1);
await ctx.scheduler.runAfter(0, internal.chat.getWikipediaSummary, {
topic,
});
}
},
});
// ADD HERE 2 !!!
export const getMessages = query({
args: {},
handler: async (ctx) => {
// Get most recent messages first
const messages = await ctx.db.query("messages").order("desc").take(50);
// Reverse the list so that it's in a chronological order.
return messages.reverse();
},
});
// ADD HERE 3 !!!
export const getWikipediaSummary = internalAction({
args: { topic: v.string() },
handler: async (ctx, args) => {
const response = await fetch(
"https://en.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles=" +
args.topic,
);
const summary = getSummaryFromJSON(await response.json());
await ctx.scheduler.runAfter(0, api.chat.sendMessage, {
user: "Wikipedia",
body: summary,
});
},
});
// ADD HERE 3 !!!
function getSummaryFromJSON(data: any) {
const firstPageId = Object.keys(data.query.pages)[0];
return data.query.pages[firstPageId].extract;
}
ダッシュボード で、getWikipediaSummary
関数をテストすることができます。
Functions > getWikipediaSummary
と選択し、Run Functionをクリック、
topicに検索ワードを入力し、Run Actionをクリックします。

Wikipediaにキーワードを送り、サマリーがチャットに返信される。

ConvexのSchedulerとActionのイメージ

(出典:https://docs.convex.dev/tutorial/actions#the-scheduler-actions-and-the-sync-engine)
データベース操作はクエリとミューテーションのみで行います。スケジューラは、この間にアクションを挟んで複雑なワークフローを構築することを可能にします。
Convexのバックエンドの役割分担
- アクション: AWS Lambdaのような通常のサーバーレス関数で、外部APIの呼び出しなど、不確実な外部とのやり取りを担います。
- クエリとミューテーション: データベースのトランザクションを保証する役割を持ち、高速で機敏な同期エンジンの一部です。データベースとの通信は、必ずこの2つを経由しなければなりません。
スケールするアプリケーションを構築するには、外部との通信を行うアクションの作業を最小限に抑え、主要なロジックをクエリとミューテーションで処理するのが最善の方法です。これにより、Convexは高いスループットを維持できます。