This plugin allows developers to create tRPC server on Cloudflare Page Function rapidly.
You can see demo site on https://cloudflare-pages-plugin-trpc.pages.dev.
If you have any tRPC router, just set it into this plugin!
For example, you have router as like as below:
// router.ts
import { initTRPC } from "@trpc/server";
const t = initTRPC.create();
const appRouter = t.router({
hello: t.procedure.query(() => "world"),
});
export type AppRouter = typeof appRouter;
You can deploy it to Cloudflare Pages Function right now.
import { router } from "./router.ts";
import tRPCPlugin from "cloudflare-pages-plugin";
// That's it!
export const onRequest: PagesFunction = tRPCPlugin({ router });
More practical code deployed to the demo site can be found in the /examples folder.
Cloudflare has provided bindings to allow your Workers to interact with resources on the Workers' platform.
And this plugin allows you to interact with any resources on the Workers platform from the tRPC context with only writing a bit of code.
For example, if you write the below code, then you can use Cloudflare D1 from the tRPC context:
import { initTRPC } from "@trpc/server";
import { z } from "zod";
import tRPCPlugin, {
FetchCreateContextWithCloudflareEnvFnOptions,
} from "cloudflare-pages-plugin-trpc";
// Define binding to allow your worker to interact with Cloudflare D1.
export interface Env {
DB: D1Database;
}
// Use the `FetchCreateContextWithCloudflareEnvFnOptions` type to function parameter to createContext, and it can expose Cloudflare Env to tRPC's context.
const createContext = async ({
req,
env,
}: FetchCreateContextWithCloudflareEnvFnOptions<Env>) => {
return {
db: env.DB,
};
};
// After that, it is enough to write it in the same way as for a normal tRPC
type Context = inferAsyncReturnType<typeof createContext>;
const t = initTRPC.context<Context>().create();
const posts = t.router({
create: t.procedure
.input(z.object({ title: z.string(), body: z.string() }))
.mutation(async ({ input, ctx }) => {
// You can use Cloudflare D1 from the tRPC context!!
const result = await ctx.env.DB.prepare(
"INSERT INTO posts (title, body) VALUES (?, ?)"
)
.bind(input.title, input.body)
.run();
if (!result.success) {
throw new Error(result.error);
}
}),
list: t.procedure.query(async ({ ctx }) => {
const { results: posts } = await ctx.env.DB.prepare(
"SELECT * FROM posts"
).all();
return {
posts,
};
}),
});
const appRouter = t.router({
posts,
});
export const onRequest: PagesFunction<Env> = tRPCPlugin({
router: appRouter,
endpoint: "/api/trpc",
});
tRPC is library that allows End-to-end typesafe APIs made easy. There are many resource to explain tRPC concept, history and what it try to resolve, but I highly recommend that you try to quick demo first.
Of course, you can see tRPC document on trpc.io.
I've sometimes contributed tRPC, so I also created a pull request that this plugin into tRPC package, and I discussed @KATT who creator of tRPC and @sachinraja who maintainer of tRPC, and result, it's prefer to provide as individual package.
So, I'll continue to actively follow and maintain tRPC updates.
-
Write documents
- deploy guide
-
Testing
I'm considering how test it.