Skip to content

Commit

Permalink
refactor: make context generic
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierniki committed Sep 5, 2023
1 parent 4179409 commit 856c374
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 7 deletions.
41 changes: 41 additions & 0 deletions app/api/algolia-webhook/publish/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import algolia from "algoliasearch"
import { env } from "env.mjs"
import { NextResponse } from "next/server"
import { slateToText } from "utils/slateToText"
import { z } from "zod"
import { withValidSignature } from "../withValidSignature"
import { NextRequestWithValidBody, withBodySchema } from "../withBodySchema"

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

async function handleAlgoliaWebhook(req: NextRequestWithValidBody<z.infer<typeof bodySchema>>) {
try {
const article = req.validBody.data

const indexingResults = await Promise.allSettled(
article.localizations.map(async ({ locale, title, content }) => {
const index = client.initIndex(`articles-${locale}`)
await index.saveObject({
objectID: article.id,
title,
content: slateToText(content),
})

return { title, locale }
})
)

return NextResponse.json({ result: indexingResults }, { status: 201 })
} catch (err) {
return NextResponse.json({ message: "Unexpected Error" }, { status: 500 })
}
}

const bodySchema = z.object({
data: z.object({
localizations: z.array(z.object({ content: z.any(), title: z.string(), locale: z.string() })),
id: z.string(),
}),
})

export const POST = withValidSignature(withBodySchema(handleAlgoliaWebhook, bodySchema))
41 changes: 41 additions & 0 deletions app/api/algolia-webhook/unpublish/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import algolia from "algoliasearch"
import { env } from "env.mjs"
import { NextResponse } from "next/server"
import { slateToText } from "utils/slateToText"
import { z } from "zod"
import { withValidSignature } from "../withValidSignature"
import { NextRequestWithValidBody, withBodySchema } from "../withBodySchema"

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

async function handleAlgoliaWebhook(req: NextRequestWithValidBody<z.infer<typeof bodySchema>>) {
try {
const article = req.validBody.data

const indexingResults = await Promise.allSettled(
article.localizations.map(async ({ locale, title, content }) => {
const index = client.initIndex(`articles-${locale}`)
await index.saveObject({
objectID: article.id,
title,
content: slateToText(content),
})

return { title, locale }
})
)

return NextResponse.json({ result: indexingResults }, { status: 201 })
} catch (err) {
return NextResponse.json({ message: "Unexpected Error" }, { status: 500 })
}
}

const bodySchema = z.object({
data: z.object({
localizations: z.array(z.object({ content: z.any(), title: z.string(), locale: z.string() })),
id: z.string(),
}),
})

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

export const withBodySchema =
<T>(fun: (req: NextRequestWithValidBody<T>, context?: any) => Promise<NextResponse>, schema: Zod.Schema<T>) =>
async (req: NextRequest | NextRequestWithBody, context?: any) => {
<TBody, TContext>(
fun: (req: NextRequestWithValidBody<TBody>, context?: TContext) => Promise<NextResponse>,
schema: Zod.Schema<TBody>
) =>
async (req: NextRequest | NextRequestWithBody, context?: TContext) => {
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 })
const reqWithBody: NextRequestWithValidBody<TBody> = Object.assign(req, { validBody: parseResult.data })
return fun(reqWithBody, context)
} catch {
return NextResponse.json({ message: "Bad Request" }, { status: 400 })
Expand Down
4 changes: 2 additions & 2 deletions app/api/algolia-webhook/withValidSignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ 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) => {
<TContext>(fun: (req: NextRequestWithBody, context?: TContext) => Promise<NextResponse>) =>
async (req: NextRequest, context?: TContext) => {
const authHeader = req.headers.get("gcms-signature")
if (!authHeader) return NextResponse.json({ message: "Unauthorized" }, { status: 401 })
const parsedBody = await req.json()
Expand Down

0 comments on commit 856c374

Please sign in to comment.