Skip to content

Commit

Permalink
Implement openAPI for listing resources by endUserId
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyxiao committed Oct 22, 2023
1 parent fa3fc3a commit 7e8608e
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 31 deletions.
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@
"cac": "6.7.12",
"keytar": "7.9.0",
"micro": "9.3.5-canary.3",
"ngrok": "4.3.3"
"ngrok": "5.0.0-beta.2"
}
}
5 changes: 4 additions & 1 deletion apps/web/app/(admin)/(authenticated)/api-access/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Link from 'next/link'

import {kApikeyHeader, kApikeyUrlParam} from '@usevenice/app-config/constants'
import {Input, Label} from '@usevenice/ui/shadcn'

import {cn} from '@/lib-client/ui-utils'
Expand Down Expand Up @@ -37,7 +38,9 @@ export default async function ApiKeyPage() {
</Label>
<Input className="font-mono" readOnly value={apikey} />
</div>
<p className="mt-4">More docs coming soon</p>
<p className="mt-4">
Use `{kApikeyHeader}` header or `{kApikeyUrlParam}` url param{' '}
</p>
</div>
)
}
1 change: 1 addition & 0 deletions apps/web/pages/api/debug.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {NextApiHandler} from 'next'

export default ((_req, res) => {
console.log('req.query', _req.query)
res.send({ok: true})
}) satisfies NextApiHandler
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"jest-date-mock": "1.0.8",
"jest-watch-typeahead": "2.1.1",
"lint-staged": "13.0.3",
"ngrok": "4.3.3",
"ngrok": "5.0.0-beta.2",
"npm-run-all": "4.1.5",
"openapi-zod-client": "1.6.3",
"prettier": "2.8.8",
Expand Down
1 change: 1 addition & 0 deletions packages/cdk-core/id.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type Id<TName extends string = string> = {
export const zUserId = zId('user')
export type UserId = z.infer<typeof zUserId>

/** trpc-openapi limits us from using .brand https://share.cleanshot.com/Mf4F9xwZ */
export const zEndUserId = z.string().min(1).brand<'end_user'>()
export type EndUserId = z.infer<typeof zEndUserId>

Expand Down
5 changes: 4 additions & 1 deletion packages/cdk-core/metaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,13 @@ export interface MetaService {
limit?: number
offset?: number
}) => Promise<ReadonlyArray<ZRaw['institution']>>
/** TODO: Implement limit & offset */
findPipelines: (options: {
resourceIds?: Array<Id['reso']>
secondsSinceLastSync?: number
}) => Promise<ReadonlyArray<ZRaw['pipeline']>>
/** Id is used to check RLS policy right now for end user */
listIntegrationIds: (opts?: {id?: Id['int']}) => Promise<ReadonlyArray<Id['int']>>
listIntegrationIds: (opts?: {
id?: Id['int']
}) => Promise<ReadonlyArray<Id['int']>>
}
6 changes: 6 additions & 0 deletions packages/engine-backend/router/_schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {z} from '@usevenice/util'

export const zListParams = z.object({
limit: z.number().optional(),
offset: z.number().optional(),
})
31 changes: 20 additions & 11 deletions packages/engine-backend/router/protectedRouter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {TRPCError} from '@trpc/server'

import type {
ZRaw} from '@usevenice/cdk-core';
import type {ZRaw} from '@usevenice/cdk-core'
import {zEndUserId} from '@usevenice/cdk-core'
import {
extractId,
sync,
Expand All @@ -17,6 +17,7 @@ import {inngest, zEvent} from '../events'
import {parseWebhookRequest} from '../parseWebhookRequest'
import {zSyncOptions} from '../types'
import {protectedProcedure, trpc} from './_base'
import {zListParams} from './_schemas'

export {type inferProcedureInput} from '@trpc/server'

Expand All @@ -36,18 +37,24 @@ export const protectedRouter = trpc.router({
}),
listResources: protectedProcedure
.meta({openapi: {method: 'GET', path: '/resources'}})
.input(z.object({}).optional())
.input(zListParams.extend({endUserId: zEndUserId.optional()}).optional())
.output(z.array(zRaw.resource))
.query(async ({ctx}) => {
const resources = await ctx.helpers.metaService.tables.resource.list({})
.query(async ({input = {}, ctx}) => {
const resources = await ctx.helpers.metaService.tables.resource.list(
input,
)
return resources as Array<ZRaw['resource']>
}),
listPipelines: protectedProcedure
.meta({openapi: {method: 'GET', path: '/pipelines'}})
.input(z.object({}).optional())
.input(
zListParams
.extend({resourceIds: z.array(zId('reso')).optional()})
.optional(),
)
.output(z.array(zRaw.pipeline))
.query(async ({ctx}) => {
const pipelines = await ctx.helpers.metaService.tables.pipeline.list({})
.query(async ({input = {}, ctx}) => {
const pipelines = await ctx.helpers.metaService.findPipelines(input)
return pipelines as Array<ZRaw['pipeline']>
}),
deletePipeline: protectedProcedure
Expand All @@ -59,11 +66,13 @@ export const protectedRouter = trpc.router({
return true as const
}),
listConnections: protectedProcedure
.input(z.object({}).optional())
.query(async ({ctx}) => {
.input(zListParams.extend({endUserId: zEndUserId.optional()}).optional())
.query(async ({input = {}, ctx}) => {
// Add info about what it takes to `reconnect` here for resources which
// has disconnected
const resources = await ctx.helpers.metaService.tables.resource.list({})
const resources = await ctx.helpers.metaService.tables.resource.list(
input,
)
const [institutions, _pipelines] = await Promise.all([
ctx.helpers.metaService.tables.institution.list({
ids: R.compact(resources.map((c) => c.institutionId)),
Expand Down
4 changes: 4 additions & 0 deletions packages/util/zod-jsonschema-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export function ensureNodeTitle<T = unknown>(jsonSchema: T) {
return jsonSchema
}

/**
* TODO: Consider switching to this repo to allow better actual customizations
* https://github.com/anatine/zod-plugins/tree/main/packages/zod-openapi
*/
export function zodToJsonSchema(schema: z.ZodTypeAny) {
// Defaulting title should occur last, this way we don't end up with extraneous one
return defaultTitleAsJsonPath(ensureNodeTitle(_zodToJsonSchema(schema)))
Expand Down
19 changes: 19 additions & 0 deletions patches/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,22 @@ index d93e38e020d89bef3e615c44fe687b10c8874417..956b349a0dda132bcdd7c255e8ae9946
import { OpenAPIV3 } from 'openapi-types';
import { ZodIssue } from 'zod';
export type OpenApiMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
diff --git a/dist/utils/zod.js b/dist/utils/zod.js
index f9b479f56b52ceea1cab9b581c7dcd27d500d5d6..c848fa8030d6e275608863333fe9f61879692f16 100644
--- a/dist/utils/zod.js
+++ b/dist/utils/zod.js
@@ -27,6 +27,14 @@ const instanceofZodTypeLikeVoid = (type) => {
};
exports.instanceofZodTypeLikeVoid = instanceofZodTypeLikeVoid;
const unwrapZodType = (type, unwrapPreprocess) => {
+ // This will fail at runtime because we are not properly coercing to array type yet
+ if ((0, exports.instanceofZodTypeKind)(type, zod_1.z.ZodFirstPartyTypeKind.ZodArray)) {
+ return (0, exports.unwrapZodType)(type.element, unwrapPreprocess);
+ }
+ // Works fine
+ if ((0, exports.instanceofZodTypeKind)(type, zod_1.z.ZodFirstPartyTypeKind.ZodBrand)) {
+ return (0, exports.unwrapZodType)(type.unwrap(), unwrapPreprocess);
+ }
if ((0, exports.instanceofZodTypeKind)(type, zod_1.z.ZodFirstPartyTypeKind.ZodOptional)) {
return (0, exports.unwrapZodType)(type.unwrap(), unwrapPreprocess);
}
29 changes: 13 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7e8608e

Please sign in to comment.