chore: refactor hono structure

This commit is contained in:
Lars Hampe 2024-10-24 22:15:47 +02:00
parent 2169d29c17
commit 0951d06607
8 changed files with 62 additions and 91 deletions

View File

@ -1,16 +1,16 @@
import { db, page } from '@boring.tools/database' import { db, page } from '@boring.tools/database'
import { PageByIdParams, PageOutput } from '@boring.tools/schema'
import { createRoute } from '@hono/zod-openapi' import { createRoute } from '@hono/zod-openapi'
import { and, eq } from 'drizzle-orm' import { and, eq } from 'drizzle-orm'
import { PageByIdParams, PageOutput } from '@boring.tools/schema'
import { HTTPException } from 'hono/http-exception' import { HTTPException } from 'hono/http-exception'
import { verifyAuthentication } from '../utils/authentication' import { verifyAuthentication } from '../utils/authentication'
import type { pageApi } from './index' import type { pageApi } from './index'
const getRoute = createRoute({ const route = createRoute({
method: 'get', method: 'get',
tags: ['page'], tags: ['page'],
description: 'Get a page', description: 'Get a page by id',
path: '/:id', path: '/:id',
request: { request: {
params: PageByIdParams, params: PageByIdParams,
@ -33,8 +33,8 @@ const getRoute = createRoute({
}, },
}) })
export function registerPageById(api: typeof pageApi) { export const registerPageById = (api: typeof pageApi) => {
return api.openapi(getRoute, async (c) => { return api.openapi(route, async (c) => {
const userId = verifyAuthentication(c) const userId = verifyAuthentication(c)
const { id } = c.req.valid('param') const { id } = c.req.valid('param')

View File

@ -1,12 +1,12 @@
import { changelogs_to_pages, db, page } from '@boring.tools/database' import { changelogs_to_pages, db, page } from '@boring.tools/database'
import { createRoute, type z } from '@hono/zod-openapi'
import { PageCreateInput, PageOutput } from '@boring.tools/schema' import { PageCreateInput, PageOutput } from '@boring.tools/schema'
import { createRoute, type z } from '@hono/zod-openapi'
import { HTTPException } from 'hono/http-exception' import { HTTPException } from 'hono/http-exception'
import { verifyAuthentication } from '../utils/authentication' import { verifyAuthentication } from '../utils/authentication'
import type { pageApi } from './index' import type { pageApi } from './index'
const getRoute = createRoute({ const route = createRoute({
method: 'post', method: 'post',
tags: ['page'], tags: ['page'],
description: 'Create a page', description: 'Create a page',
@ -36,8 +36,8 @@ const getRoute = createRoute({
}, },
}) })
export function registerPageCreate(api: typeof pageApi) { export const registerPageCreate = (api: typeof pageApi) => {
return api.openapi(getRoute, async (c) => { return api.openapi(route, async (c) => {
const userId = verifyAuthentication(c) const userId = verifyAuthentication(c)
const { changelogIds, ...rest }: z.infer<typeof PageCreateInput> = const { changelogIds, ...rest }: z.infer<typeof PageCreateInput> =

View File

@ -1,5 +1,5 @@
import { db, page } from '@boring.tools/database' import { db, page } from '@boring.tools/database'
import { createRoute, z } from '@hono/zod-openapi' import { createRoute } from '@hono/zod-openapi'
import { and, eq } from 'drizzle-orm' import { and, eq } from 'drizzle-orm'
import { PageListOutput } from '@boring.tools/schema' import { PageListOutput } from '@boring.tools/schema'
@ -30,7 +30,7 @@ const route = createRoute({
}, },
}) })
export function registerPageList(api: typeof pageApi) { export const registerPageList = (api: typeof pageApi) => {
return api.openapi(route, async (c) => { return api.openapi(route, async (c) => {
const userId = verifyAuthentication(c) const userId = verifyAuthentication(c)

View File

@ -6,7 +6,7 @@ import { PagePublicOutput, PagePublicParams } from '@boring.tools/schema'
import { HTTPException } from 'hono/http-exception' import { HTTPException } from 'hono/http-exception'
import type { pageApi } from './index' import type { pageApi } from './index'
const getRoute = createRoute({ const route = createRoute({
method: 'get', method: 'get',
tags: ['page'], tags: ['page'],
description: 'Get a page', description: 'Get a page',
@ -32,8 +32,8 @@ const getRoute = createRoute({
}, },
}) })
export function registerPagePublic(api: typeof pageApi) { export const registerPagePublic = (api: typeof pageApi) => {
return api.openapi(getRoute, async (c) => { return api.openapi(route, async (c) => {
const { id } = c.req.valid('param') const { id } = c.req.valid('param')
const result = await db.query.page.findFirst({ const result = await db.query.page.findFirst({

View File

@ -11,7 +11,7 @@ import { HTTPException } from 'hono/http-exception'
import { verifyAuthentication } from '../utils/authentication' import { verifyAuthentication } from '../utils/authentication'
import type { pageApi } from './index' import type { pageApi } from './index'
const getRoute = createRoute({ const route = createRoute({
method: 'put', method: 'put',
tags: ['page'], tags: ['page'],
description: 'Update a page', description: 'Update a page',
@ -42,8 +42,8 @@ const getRoute = createRoute({
}, },
}) })
export function registerPageUpdate(api: typeof pageApi) { export const registerPageUpdate = (api: typeof pageApi) => {
return api.openapi(getRoute, async (c) => { return api.openapi(route, async (c) => {
const userId = verifyAuthentication(c) const userId = verifyAuthentication(c)
const { id } = c.req.valid('param') const { id } = c.req.valid('param')

View File

@ -1,11 +1,13 @@
import { type UserSelect, db, user as userDb } from '@boring.tools/database' import { db, user as userDb } from '@boring.tools/database'
import { UserOutput } from '@boring.tools/schema' import { UserOutput } from '@boring.tools/schema'
import { createRoute } from '@hono/zod-openapi' import { createRoute } from '@hono/zod-openapi'
import { eq } from 'drizzle-orm' import { eq } from 'drizzle-orm'
import type { userApi } from '.'
export const route = createRoute({ const route = createRoute({
method: 'get', method: 'get',
path: '/', path: '/',
tags: ['user'],
responses: { responses: {
200: { 200: {
content: { content: {
@ -22,19 +24,17 @@ export const route = createRoute({
}, },
}) })
export const func = async ({ user }: { user: UserSelect }) => { export const registerUserGet = (api: typeof userApi) => {
const result = await db.query.user.findFirst({ return api.openapi(route, async (c) => {
where: eq(userDb.id, user.id), const user = c.get('user')
const result = await db.query.user.findFirst({
where: eq(userDb.id, user.id),
})
if (!result) {
throw new Error('User not found')
}
return c.json(result, 200)
}) })
if (!result) {
throw new Error('User not found')
}
return result
}
export default {
route,
func,
} }

View File

@ -1,48 +1,16 @@
import { logger } from '@boring.tools/logger'
import { OpenAPIHono } from '@hono/zod-openapi' import { OpenAPIHono } from '@hono/zod-openapi'
import { Webhook } from 'svix'
import type { Variables } from '..' import type { Variables } from '..'
import { type ContextModule, captureSentry } from '../utils/sentry' import type { ContextModule } from '../utils/sentry'
import get from './get' import { registerUserGet } from './get'
import webhook from './webhook' import { registerUserWebhook } from './webhook'
const app = new OpenAPIHono<{ Variables: Variables }>() export const userApi = new OpenAPIHono<{ Variables: Variables }>()
const module: ContextModule = { const module: ContextModule = {
name: 'user', name: 'user',
} }
app.openapi(get.route, async (c) => { registerUserGet(userApi)
const user = c.get('user') registerUserWebhook(userApi)
try {
const result = await get.func({ user })
return c.json(result, 201)
} catch (error) {
return captureSentry({
c,
error,
module,
user,
})
}
})
app.openapi(webhook.route, async (c) => { export default userApi
try {
const wh = new Webhook(import.meta.env.CLERK_WEBHOOK_SECRET as string)
const payload = await c.req.json()
const headers = c.req.header()
const verifiedPayload = wh.verify(JSON.stringify(payload), headers)
const result = await webhook.func({ payload: verifiedPayload })
logger.info('Clerk Webhook', result)
return c.json(result, 200)
} catch (error) {
return captureSentry({
c,
error,
module,
})
}
})
export default app

View File

@ -3,10 +3,13 @@ import { logger } from '@boring.tools/logger'
import { UserOutput, UserWebhookInput } from '@boring.tools/schema' import { UserOutput, UserWebhookInput } from '@boring.tools/schema'
import { createRoute, type z } from '@hono/zod-openapi' import { createRoute, type z } from '@hono/zod-openapi'
import { HTTPException } from 'hono/http-exception' import { HTTPException } from 'hono/http-exception'
import { Webhook } from 'svix'
import type userApi from '.'
export const route = createRoute({ const route = createRoute({
method: 'post', method: 'post',
path: '/webhook', path: '/webhook',
tags: ['user'],
request: { request: {
body: { body: {
content: { content: {
@ -59,20 +62,20 @@ const userCreate = async ({
} }
} }
export const func = async ({ export const registerUserWebhook = (api: typeof userApi) => {
payload, return api.openapi(route, async (c) => {
}: { const wh = new Webhook(import.meta.env.CLERK_WEBHOOK_SECRET as string)
payload: z.infer<typeof UserWebhookInput> const payload = await c.req.json()
}) => { const headers = c.req.header()
switch (payload.type) { const verifiedPayload = wh.verify(JSON.stringify(payload), headers)
case 'user.created': switch (verifiedPayload.type) {
return userCreate({ payload }) case 'user.created': {
default: const result = await userCreate({ payload: verifiedPayload })
throw new HTTPException(404, { message: 'Webhook type not supported' }) logger.info('Clerk Webhook', result)
} return c.json(result, 200)
} }
default:
export default { throw new HTTPException(404, { message: 'Webhook type not supported' })
route, }
func, })
} }