Skip to content

Commit

Permalink
Got openAPI working at /api/openapi
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyxiao committed Oct 14, 2023
1 parent 3e41834 commit 4cbc132
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 36 deletions.
21 changes: 20 additions & 1 deletion apps/web/lib-server/appRouter.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import {clerkClient} from '@clerk/nextjs'
import {TRPCError} from '@trpc/server'
import {generateOpenApiDocument} from 'trpc-openapi'

import {getServerUrl} from '@usevenice/app-config/constants'
import {flatRouter} from '@usevenice/engine-backend'
import {adminProcedure, trpc} from '@usevenice/engine-backend/router/_base'
import {
adminProcedure,
publicProcedure,
trpc,
} from '@usevenice/engine-backend/router/_base'
import {z} from '@usevenice/util'

import {zAuth} from '@/lib-common/schemas'

Expand All @@ -16,8 +23,20 @@ const customRouter = trpc.router({
const org = await clerkClient.organizations.updateOrganization(id, update)
return org
}),

getOpenapiDocument: publicProcedure
.meta({openapi: {method: 'GET', path: '/'}})
.input(z.void())
.output(z.unknown())
.query(() => openApiDocument),
})

export const appRouter = trpc.mergeRouters(flatRouter, customRouter)

export const openApiDocument = generateOpenApiDocument(appRouter, {
title: 'Venice OpenAPI',
version: '0.0.0',
baseUrl: getServerUrl(null) + '/api/openapi',
})

export type AppRouter = typeof appRouter
3 changes: 2 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"superjson": "1.9.1",
"swagger2openapi": "7.0.8"
"swagger2openapi": "7.0.8",
"trpc-openapi": "1.2.0"
},
"devDependencies": {
"@sentry/cli": "2.13.0",
Expand Down
27 changes: 27 additions & 0 deletions apps/web/pages/api/openapi/[[...trpc]].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import '@usevenice/app-config/register.node'

import type {NextApiHandler} from 'next'
import {createOpenApiNextHandler} from 'trpc-openapi'

import {respondToCORS} from '@/lib-server'
import {appRouter} from '@/lib-server/appRouter'

import {createContext, onError} from '../trpc/[...trpc]'

const handler = createOpenApiNextHandler({
// not sure why this cast is needed...
router: appRouter as any,
createContext,
onError,
})

export default (function trpcHandler(req, res) {
if (respondToCORS(req, res)) {
return
}
// allow the root document to work.
if (!req.query['trpc']) {
req.query['trpc'] = ''
}
return handler(req, res)
} satisfies NextApiHandler)
24 changes: 16 additions & 8 deletions apps/web/pages/api/trpc/[...trpc].ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,24 @@ import {parseWebhookRequest} from '@usevenice/engine-backend'
import {appRouter} from '@/lib-server/appRouter'
import {respondToCORS, serverGetViewer} from '@/lib-server/server-helpers'

export const createContext: Parameters<
typeof trpcNext.createNextApiHandler
>[0]['createContext'] = async ({req, res}) => {
const viewer = await serverGetViewer({req, res})
console.log('[trpc.createContext]', {query: req.query, viewer})
return contextFactory.fromViewer(viewer)
}

export const onError: Parameters<
typeof trpcNext.createNextApiHandler
>[0]['onError'] = ({error}) => {
console.warn('error', error)
}

const handler = trpcNext.createNextApiHandler({
router: appRouter,
createContext: async ({req, res}) => {
const viewer = await serverGetViewer({req, res})
console.log('[trpc.createContext]', {query: req.query, viewer})
return contextFactory.fromViewer(viewer)
},
onError: ({error}) => {
console.warn('error', error)
},
createContext,
onError,
})

export default (function trpcHandler(req, res) {
Expand Down
4 changes: 3 additions & 1 deletion packages/engine-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
"@usevenice/util": "workspace:*",
"inngest": "1.3.1"
},
"devDependencies": {}
"devDependencies": {
"trpc-openapi": "1.2.0"
}
}
6 changes: 3 additions & 3 deletions packages/engine-backend/router/_base.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {initTRPC, TRPCError} from '@trpc/server'
import type {OpenApiMeta} from 'trpc-openapi'

import {getExtEndUserId, hasRole} from '@usevenice/cdk-core'

import type {RouterContext} from '../context'

/** TODO: Use OpenApiMeta from https://github.com/jlalmes/trpc-openapi */
interface OpenApiMeta {}
interface RouterMeta extends OpenApiMeta {}

export const trpc = initTRPC
.context<RouterContext>()
.meta<OpenApiMeta>()
.meta<RouterMeta>()
// For client side to be able to import runtime schema from server side also
.create({allowOutsideOfServer: true})

Expand Down
8 changes: 5 additions & 3 deletions packages/engine-backend/router/adminRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@ export const adminRouterSchema = {
} satisfies Record<string, {input?: z.ZodTypeAny; output?: z.ZodTypeAny}>

export const adminRouter = trpc.router({
adminListIntegrations: adminProcedure.query(async ({ctx}) =>
ctx.helpers.list('integration', {}),
),
adminListIntegrations: adminProcedure
.meta({openapi: {method: 'GET', path: '/integrations'}})
.input(z.void())
.output(z.array(zRaw.integration))
.query(async ({ctx}) => ctx.helpers.list('integration', {})),
adminUpsertPipeline: adminProcedure
.input(
zRaw.pipeline
Expand Down
8 changes: 6 additions & 2 deletions packages/engine-backend/router/publicRouter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import {metaForProvider} from '@usevenice/cdk-core'
import {R} from '@usevenice/util'
import {R, z} from '@usevenice/util'

import {publicProcedure, trpc} from './_base'

export const publicRouter = trpc.router({
health: publicProcedure.query(() => 'Ok ' + new Date().toISOString()),
health: publicProcedure
.meta({openapi: {method: 'GET', path: '/health'}})
.input(z.void())
.output(z.string())
.query(() => 'Ok ' + new Date().toISOString()),
getIntegrationCatalog: publicProcedure.query(({ctx}) =>
R.mapValues(ctx.providerMap, (provider) => metaForProvider(provider)),
),
Expand Down
Loading

0 comments on commit 4cbc132

Please sign in to comment.