Skip to content

Commit

Permalink
refactor: add HoF to route handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierniki committed Sep 5, 2023
1 parent 33c26e1 commit 4179409
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 18 deletions.
24 changes: 6 additions & 18 deletions app/api/algolia-webhook/route.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
import { verifyWebhookSignature } from "@hygraph/utils"
import algolia from "algoliasearch"
import { env } from "env.mjs"
import { NextRequest, NextResponse } from "next/server"
import { slateToText } from "utils/slateToText"
import { z } from "zod"
import { NextRequestWithValidBody, withBodySchema } from "./withBodySchema"
import { withValidSignature } from "./withValidSignature"

const client = algolia(env.ALGOLIA_API_ID, env.ALGOLIA_API_KEY)

export async function POST(req: NextRequest) {
const authHeader = req.headers.get("gcms-signature")
if (!authHeader) return NextResponse.json({ message: "Unauthorized" }, { status: 401 })

async function handleAlgoliaWebhook(req: NextRequestWithValidBody<z.infer<typeof bodySchema>>) {
try {
const publishedData = await req.json()

const isSignatureValid = verifyWebhookSignature({
body: publishedData,
signature: authHeader,
secret: env.HYGRAPH_WEBOOK_SECRET,
})
if (!isSignatureValid) return NextResponse.json({ message: "Unauthorized" }, { status: 401 })

const parseResult = bodySchema.safeParse(publishedData)
if (!parseResult.success) return NextResponse.json({ message: "Bad Request" }, { status: 400 })

const article = parseResult.data.data
const article = req.validBody.data

const indexingResults = await Promise.allSettled(
article.localizations.map(async ({ locale, title, content }) => {
Expand All @@ -51,3 +37,5 @@ const bodySchema = z.object({
id: z.string(),
}),
})

export const POST = withValidSignature(withBodySchema(handleAlgoliaWebhook, bodySchema))
19 changes: 19 additions & 0 deletions app/api/algolia-webhook/withBodySchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextResponse, NextRequest } from "next/server"
import { NextRequestWithBody, hasParsedBody } from "./withValidSignature"

export const withBodySchema =
<T>(fun: (req: NextRequestWithValidBody<T>, context?: any) => Promise<NextResponse>, schema: Zod.Schema<T>) =>
async (req: NextRequest | NextRequestWithBody, context?: any) => {
try {
const hasBody = hasParsedBody(req)
const parseResult = schema.safeParse(hasBody ? req.body : await req.json())
if (!parseResult.success) return NextResponse.json({ message: "Bad Request" }, { status: 400 })

const reqWithBody: NextRequestWithValidBody<T> = Object.assign(req, { validBody: parseResult.data })
return fun(reqWithBody, context)
} catch {
return NextResponse.json({ message: "Bad Request" }, { status: 400 })
}
}

export type NextRequestWithValidBody<T> = NextRequest & { validBody: T }
26 changes: 26 additions & 0 deletions app/api/algolia-webhook/withValidSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { verifyWebhookSignature } from "@hygraph/utils"
import { env } from "env.mjs"
import { NextRequest, NextResponse } from "next/server"

export const withValidSignature =
(fun: (req: NextRequestWithBody, context?: any) => Promise<NextResponse>) =>
async (req: NextRequest, context?: any) => {
const authHeader = req.headers.get("gcms-signature")
if (!authHeader) return NextResponse.json({ message: "Unauthorized" }, { status: 401 })
const parsedBody = await req.json()

const isSignatureValid = verifyWebhookSignature({
body: parsedBody,
signature: authHeader,
secret: env.HYGRAPH_WEBOOK_SECRET,
})
if (!isSignatureValid) return NextResponse.json({ message: "Unauthorized" }, { status: 401 })

const reqWithBody: NextRequestWithBody = Object.assign(req, { parsedBody })
return fun(reqWithBody, context)
}

export type NextRequestWithBody = NextRequest & { parsedBody: unknown }

export const hasParsedBody = (req: NextRequestWithBody | NextRequest): req is NextRequestWithBody =>
Boolean((req as NextRequestWithBody).body)

0 comments on commit 4179409

Please sign in to comment.