From 5163714d105bce6c73598a710a5b05bbd1e1e545 Mon Sep 17 00:00:00 2001 From: Emil Widlund Date: Thu, 16 May 2024 16:19:41 +0200 Subject: [PATCH] implement dereferenced openapi schema --- .../[...endpoint]/APIContainer.tsx | 22 ++--- .../[...endpoint]/ResponseContainer.tsx | 16 +--- .../docs/api-reference/[...endpoint]/page.tsx | 17 +--- clients/packages/sdk/package.json | 3 +- .../sdk/scripts/dereference-schema.js | 39 +++++++++ clients/pnpm-lock.yaml | 84 +++++++++++++++++++ 6 files changed, 137 insertions(+), 44 deletions(-) create mode 100644 clients/packages/sdk/scripts/dereference-schema.js diff --git a/clients/apps/web/src/app/docs/api-reference/[...endpoint]/APIContainer.tsx b/clients/apps/web/src/app/docs/api-reference/[...endpoint]/APIContainer.tsx index 0c436a07e9..f8838f9855 100644 --- a/clients/apps/web/src/app/docs/api-reference/[...endpoint]/APIContainer.tsx +++ b/clients/apps/web/src/app/docs/api-reference/[...endpoint]/APIContainer.tsx @@ -2,7 +2,6 @@ import { CONFIG } from '@/utils/config' import { ContentPasteOutlined } from '@mui/icons-material' -import openapiSchema from '@polar-sh/sdk/openapi' import { OpenAPIV3_1 } from 'openapi-types' import Button from 'polarkit/components/ui/atoms/button' import { @@ -13,23 +12,13 @@ import { } from 'polarkit/components/ui/atoms/tabs' import { useCallback, useMemo } from 'react' -const resolveSchema = (schemaName: string) => { - return (openapiSchema as unknown as OpenAPIV3_1.Document).components - ?.schemas?.[schemaName] -} - export const requestBodyParameters = ( endpointMethod: OpenAPIV3_1.OperationObject, ) => { if (endpointMethod.requestBody && !('content' in endpointMethod.requestBody)) return undefined - return resolveSchema( - // @ts-ignore - endpointMethod.requestBody?.content['application/json'].schema?.['$ref'] - .split('/') - .pop(), - ) + return endpointMethod.requestBody?.content['application/json'].schema } export const APIContainer = ({ @@ -49,8 +38,13 @@ export const APIContainer = ({ url: string, endpoint: OpenAPIV3_1.OperationObject, ) => { - const requiredBodyParameters = requestBodyParameters(endpoint)?.properties - ? Object.entries(requestBodyParameters(endpoint)?.properties ?? {}) + const requiredBodyParameters = endpoint.requestBody?.content?.[ + 'application/json' + ].schema.properties + ? Object.entries( + endpoint.requestBody?.content?.['application/json'].schema + .properties ?? {}, + ) .map(([key]) => ({ [key]: `<${key}>`, })) diff --git a/clients/apps/web/src/app/docs/api-reference/[...endpoint]/ResponseContainer.tsx b/clients/apps/web/src/app/docs/api-reference/[...endpoint]/ResponseContainer.tsx index efbdd9fb87..1f8e7bcb87 100644 --- a/clients/apps/web/src/app/docs/api-reference/[...endpoint]/ResponseContainer.tsx +++ b/clients/apps/web/src/app/docs/api-reference/[...endpoint]/ResponseContainer.tsx @@ -1,4 +1,3 @@ -import openapiSchema from '@polar-sh/sdk/openapi' import { OpenAPIV3_1 } from 'openapi-types' import { Tabs, @@ -7,18 +6,6 @@ import { TabsTrigger, } from 'polarkit/components/ui/atoms/tabs' -export const resolveSchema = (schemaName: string) => { - return (openapiSchema as unknown as OpenAPIV3_1.Document).components - ?.schemas?.[schemaName] -} - -export const getResponseSchema = (response: OpenAPIV3_1.ResponseObject) => { - return resolveSchema( - // @ts-ignore - response.content?.['application/json'].schema?.['$ref'].split('/').pop(), - ) -} - export const ResponseContainer = ({ responses, }: { @@ -49,8 +36,7 @@ export const ResponseContainer = ({
               {JSON.stringify(
-                getResponseSchema(response as OpenAPIV3_1.ResponseObject)
-                  ?.properties,
+                response.content?.['application/json'].schema,
                 null,
                 2,
               )}
diff --git a/clients/apps/web/src/app/docs/api-reference/[...endpoint]/page.tsx b/clients/apps/web/src/app/docs/api-reference/[...endpoint]/page.tsx
index e9b41d7dab..81fadde8d8 100644
--- a/clients/apps/web/src/app/docs/api-reference/[...endpoint]/page.tsx
+++ b/clients/apps/web/src/app/docs/api-reference/[...endpoint]/page.tsx
@@ -1,6 +1,6 @@
 import openapiSchema from '@polar-sh/sdk/openapi'
 import { OpenAPIV3_1 } from 'openapi-types'
-import { PropsWithChildren, useCallback, useMemo } from 'react'
+import { PropsWithChildren, useMemo } from 'react'
 import { SchemaPathKey } from '../../APINavigation'
 import { APIContainer } from './APIContainer'
 import { ResponseContainer } from './ResponseContainer'
@@ -19,25 +19,14 @@ export default function Page({
     method
   ] as OpenAPIV3_1.OperationObject
 
-  const resolveSchema = useCallback((schemaName: string) => {
-    return (openapiSchema as unknown as OpenAPIV3_1.Document).components
-      ?.schemas?.[schemaName]
-  }, [])
-
   const requestBodyParameters = useMemo(() => {
     if (
       endpointMethod.requestBody &&
       !('content' in endpointMethod.requestBody)
     )
       return undefined
-
-    return resolveSchema(
-      // @ts-ignore
-      endpointMethod.requestBody?.content['application/json'].schema?.['$ref']
-        .split('/')
-        .pop(),
-    )
-  }, [endpointMethod, resolveSchema])
+    return endpointMethod.requestBody?.content['application/json'].schema
+  }, [endpointMethod])
 
   if (!endpointMethod) return null
 
diff --git a/clients/packages/sdk/package.json b/clients/packages/sdk/package.json
index 885080e9ab..8086938f7b 100644
--- a/clients/packages/sdk/package.json
+++ b/clients/packages/sdk/package.json
@@ -15,10 +15,11 @@
   "scripts": {
     "download": "node scripts/generate-schema.js http://127.0.0.1:8000/openapi.json openapi/source.json openapi/updated.json",
     "generate": "pnpm download && ./generate",
-    "build": "tsup src/index.ts --format cjs,esm --dts",
+    "build": "tsup src/index.ts --format cjs,esm --dts && cp -r openapi dist/openapi && node scripts/dereference-schema.js dist/openapi/source.json",
     "prepublishOnly": "pnpm run build"
   },
   "devDependencies": {
+    "@stoplight/json-ref-resolver": "^3.1.6",
     "tsconfig": "workspace:*",
     "tsup": "^7.2.0",
     "typescript": "5.3.3"
diff --git a/clients/packages/sdk/scripts/dereference-schema.js b/clients/packages/sdk/scripts/dereference-schema.js
new file mode 100644
index 0000000000..105982f4b5
--- /dev/null
+++ b/clients/packages/sdk/scripts/dereference-schema.js
@@ -0,0 +1,39 @@
+import refResolver from '@stoplight/json-ref-resolver'
+import fs from 'fs'
+
+
+const resolveRefs = async (schema) => {
+    const resolver = new refResolver.Resolver()
+    return await resolver.resolve(schema)
+}
+
+const getOpenAPISchema = async (schemaPath) => {
+    return new Promise((resolve, reject) => {
+        fs.readFile(schemaPath, 'utf8', (err, data) => {
+            if (err) {
+                reject(err)
+            }
+            resolve(JSON.parse(data))
+        })
+    
+    })
+  }
+  
+  const save = (filename, schema) => {
+    const asJson = JSON.stringify(schema, null, 4)
+    const written = fs.writeFileSync(filename, asJson)
+    return written
+  }
+  
+  const main = async (schemaPath) => {
+    let schema = await getOpenAPISchema(schemaPath)
+    schema = (await resolveRefs(schema)).result
+    save(schemaPath, schema)
+  }
+  
+  const argv = process.argv.slice(2)
+  if (argv.length !== 1) {
+    throw new Error('Args: ')
+  }
+  main(argv[0])
+  
\ No newline at end of file
diff --git a/clients/pnpm-lock.yaml b/clients/pnpm-lock.yaml
index db3d24c0a3..7a55118ce9 100644
--- a/clients/pnpm-lock.yaml
+++ b/clients/pnpm-lock.yaml
@@ -650,6 +650,10 @@ importers:
         version: 5.3.3
 
   packages/sdk:
+    dependencies:
+      '@stoplight/json-ref-resolver':
+        specifier: ^3.1.6
+        version: 3.1.6
     devDependencies:
       tsconfig:
         specifier: workspace:*
@@ -5545,6 +5549,52 @@ packages:
     dependencies:
       '@sinonjs/commons': 3.0.1
 
+  /@stoplight/json-ref-resolver@3.1.6:
+    resolution: {integrity: sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==}
+    engines: {node: '>=8.3.0'}
+    dependencies:
+      '@stoplight/json': 3.21.0
+      '@stoplight/path': 1.3.2
+      '@stoplight/types': 13.20.0
+      '@types/urijs': 1.19.25
+      dependency-graph: 0.11.0
+      fast-memoize: 2.5.2
+      immer: 9.0.21
+      lodash: 4.17.21
+      tslib: 2.6.2
+      urijs: 1.19.11
+    dev: false
+
+  /@stoplight/json@3.21.0:
+    resolution: {integrity: sha512-5O0apqJ/t4sIevXCO3SBN9AHCEKKR/Zb4gaj7wYe5863jme9g02Q0n/GhM7ZCALkL+vGPTe4ZzTETP8TFtsw3g==}
+    engines: {node: '>=8.3.0'}
+    dependencies:
+      '@stoplight/ordered-object-literal': 1.0.5
+      '@stoplight/path': 1.3.2
+      '@stoplight/types': 13.20.0
+      jsonc-parser: 2.2.1
+      lodash: 4.17.21
+      safe-stable-stringify: 1.1.1
+    dev: false
+
+  /@stoplight/ordered-object-literal@1.0.5:
+    resolution: {integrity: sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==}
+    engines: {node: '>=8'}
+    dev: false
+
+  /@stoplight/path@1.3.2:
+    resolution: {integrity: sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==}
+    engines: {node: '>=8'}
+    dev: false
+
+  /@stoplight/types@13.20.0:
+    resolution: {integrity: sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==}
+    engines: {node: ^12.20 || >=14.13}
+    dependencies:
+      '@types/json-schema': 7.0.15
+      utility-types: 3.11.0
+    dev: false
+
   /@storybook/addon-actions@8.0.1:
     resolution: {integrity: sha512-qFd1NOI9C16/Jo+7XQQXRsoTzcvKPlT6M5lU47lGLuyLwbZSp5EKxmy8+uKTnyLF/2BTAvOLZ/wYmw+Gj4VzOA==}
     dependencies:
@@ -6974,6 +7024,10 @@ packages:
   /@types/unist@3.0.2:
     resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
 
+  /@types/urijs@1.19.25:
+    resolution: {integrity: sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==}
+    dev: false
+
   /@types/uuid@9.0.8:
     resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==}
     dev: true
@@ -9731,6 +9785,11 @@ packages:
     engines: {node: '>= 0.8'}
     dev: true
 
+  /dependency-graph@0.11.0:
+    resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==}
+    engines: {node: '>= 0.6.0'}
+    dev: false
+
   /dequal@2.0.3:
     resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
     engines: {node: '>=6'}
@@ -10814,6 +10873,10 @@ packages:
     resolution: {integrity: sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==}
     dev: false
 
+  /fast-memoize@2.5.2:
+    resolution: {integrity: sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==}
+    dev: false
+
   /fast-shallow-equal@1.0.0:
     resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==}
     dev: false
@@ -11827,6 +11890,10 @@ packages:
     resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
     dev: false
 
+  /immer@9.0.21:
+    resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
+    dev: false
+
   /immutable@4.3.5:
     resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==}
 
@@ -12939,6 +13006,10 @@ packages:
     engines: {node: '>=6'}
     hasBin: true
 
+  /jsonc-parser@2.2.1:
+    resolution: {integrity: sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==}
+    dev: false
+
   /jsonc-parser@2.3.1:
     resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==}
     dev: false
@@ -16393,6 +16464,10 @@ packages:
       es-errors: 1.3.0
       is-regex: 1.1.4
 
+  /safe-stable-stringify@1.1.1:
+    resolution: {integrity: sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==}
+    dev: false
+
   /safer-buffer@2.1.2:
     resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
 
@@ -18058,6 +18133,10 @@ packages:
     dependencies:
       punycode: 2.3.1
 
+  /urijs@1.19.11:
+    resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==}
+    dev: false
+
   /url-parse@1.5.10:
     resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
     dependencies:
@@ -18127,6 +18206,11 @@ packages:
     resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==}
     dev: true
 
+  /utility-types@3.11.0:
+    resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
+    engines: {node: '>= 4'}
+    dev: false
+
   /utils-merge@1.0.1:
     resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
     engines: {node: '>= 0.4.0'}