Github Webhooks And NextJS

I recently decided to switch an internal tool from NextJS pagesrouter to app router. There’s lots of documentation about how to do that
but the part that I was surprised would be tricky was getting my api
implementation for my Github app’s webhook handler working again.

As part of the migration I moved my webhooks endpoint for github fromits original location
/pages/api/github/hooks.ts to
/app/api/github/hooks/route.ts.

In the app dir, route handlers actually take different parameters andexport different function. For one thing, you export a separate handler
for each method type (though you can double up if they handle the method
validation internally). Secondly, we are no longer receiving

NextApiRequest which is an extension of the IncomingMessageobject. Instead we are receiving the more web-friendly
Requestobject. Since NextJS now expects handlers that receive a

Request object we can no longer just export the responsefrom Probot/Octokit’s
createNodeMiddleware.

So, instead, we have to handle the reception and processing of therequest at a lower level. It looks something like this:

1import { App } from "octokit";
2import { NextRequest } from "next/server";
3import { EmitterWebhookEventName } from "@octokit/webhooks/dist-types/types";
4
5const handler = async (req: NextRequest) => {
6    const app = new App({
7        appId: process.env.APP_ID as string,
8        privateKey: Buffer.from(
9            process.env.PRIVATE_KEY || "",
10            "base64"
11        ).toString("utf8"),
12        webhooks: {
13            secret: process.env.GITHUB_WEBHOOK_SECRET as string,
14        },
15    });
16    app.webhooks.on("pull_request.opened", async ({ payload }) => {
17        try {
18            // Do something
19        } catch (e) {
20            console.error(
21                `pull_request.opened handler failed with error: ${
22                    (<Error>e).message
23                }`
24            );
25        }
26    });
27    app.webhooks.on("pull_request.edited", async ({ payload }) => {
28        try {
29            // Do something else
30        } catch (e) {
31            console.error(
32                `pull_request.edited handler failed with error: ${
33                    (<Error>e).message
34                }`
35            );
36        }
37    });
38    await app.webhooks.verifyAndReceive({
39        id: req.headers.get("X-GitHub-Delivery") as string,
40        name: req.headers.get("X-GitHub-Event") as EmitterWebhookEventName,
41        signature: req.headers.get("X-Hub-Signature-256") as string,
42        payload: await req.text(),
43    });
44    return new Response("ok");
45};
46
47export { handler as GET, handler as POST };