Browse Source

chore: move openapi validation and dereferencing to a worker (#4789)

Akash K 2 weeks ago
parent
commit
3563e1eb16

+ 48 - 6
packages/hoppscotch-common/src/helpers/import-export/import/openapi.ts

@@ -27,13 +27,19 @@ import * as S from "fp-ts/string"
 import * as O from "fp-ts/Option"
 import * as TE from "fp-ts/TaskEither"
 import * as RA from "fp-ts/ReadonlyArray"
+import * as E from "fp-ts/Either"
 import { IMPORTER_INVALID_FILE_FORMAT } from "."
 import { cloneDeep, isNumber } from "lodash-es"
 import { getStatusCodeReasonPhrase } from "~/helpers/utils/statusCodes"
 
 export const OPENAPI_DEREF_ERROR = "openapi/deref_error" as const
 
-// TODO: URL Import Support
+const worker = new Worker(
+  new URL("./workers/openapi-import-worker.ts", import.meta.url),
+  {
+    type: "module",
+  }
+)
 
 const safeParseJSON = (str: string) => O.tryCatch(() => JSON.parse(str))
 
@@ -927,10 +933,7 @@ export const hoppOpenAPIImporter = (fileContents: string[]) =>
                   throw new Error("INVALID_OPENAPI_SPEC")
                 }
 
-                const validatedDoc = await SwaggerParser.validate(docObj, {
-                  // @ts-expect-error - this is a valid option, but seems like the types are not updated
-                  continueOnError: true,
-                })
+                const validatedDoc = await validateDocs(docObj)
 
                 resultDoc.push(validatedDoc)
               } catch (err) {
@@ -969,7 +972,8 @@ export const hoppOpenAPIImporter = (fileContents: string[]) =>
             const resultDoc = []
 
             for (const docObj of docArr) {
-              const validatedDoc = await SwaggerParser.dereference(docObj)
+              const validatedDoc = await dereferenceDocs(docObj)
+
               resultDoc.push(validatedDoc)
             }
 
@@ -981,3 +985,41 @@ export const hoppOpenAPIImporter = (fileContents: string[]) =>
     ),
     TE.chainW(convertOpenApiDocsToHopp)
   )
+
+const validateDocs = (docs: any): Promise<OpenAPI.Document> => {
+  return new Promise((resolve, reject) => {
+    worker.postMessage({
+      type: "validate",
+      docs,
+    })
+
+    worker.onmessage = (event) => {
+      if (event.data.type === "VALIDATION_RESULT") {
+        if (E.isLeft(event.data.data)) {
+          reject("COULD_NOT_VALIDATE")
+        } else {
+          resolve(event.data.data.right as OpenAPI.Document)
+        }
+      }
+    }
+  })
+}
+
+const dereferenceDocs = (docs: any): Promise<OpenAPI.Document> => {
+  return new Promise((resolve, reject) => {
+    worker.postMessage({
+      type: "dereference",
+      docs,
+    })
+
+    worker.onmessage = (event) => {
+      if (event.data.type === "DEREFERENCE_RESULT") {
+        if (E.isLeft(event.data.data)) {
+          reject("COULD_NOT_DEREFERENCE")
+        } else {
+          resolve(event.data.data.right as OpenAPI.Document)
+        }
+      }
+    }
+  })
+}

+ 53 - 0
packages/hoppscotch-common/src/helpers/import-export/import/workers/openapi-import-worker.ts

@@ -0,0 +1,53 @@
+import { Buffer } from "buffer"
+import process from "process"
+
+// Set up global shims for the swagger-parser library
+self.Buffer = Buffer
+self.global = self
+self.process = process
+
+import SwaggerParser from "@apidevtools/swagger-parser"
+import * as E from "fp-ts/Either"
+
+const validateDocs = async (docs: any) => {
+  try {
+    const res = await SwaggerParser.validate(docs, {
+      // @ts-expect-error - this is a valid option, but seems like the types are not updated
+      continueOnError: true,
+    })
+
+    return E.right(res)
+  } catch (error) {
+    return E.left("COULD_NOT_VALIDATE" as const)
+  }
+}
+
+const dereferenceDocs = async (docs: any) => {
+  try {
+    const res = await SwaggerParser.dereference(docs)
+
+    return E.right(res)
+  } catch (error) {
+    return E.left("COULD_NOT_DEREFERENCE" as const)
+  }
+}
+
+self.addEventListener("message", async (event) => {
+  if (event.data.type === "validate") {
+    const res = await validateDocs(event.data.docs)
+
+    self.postMessage({
+      type: "VALIDATION_RESULT",
+      data: res,
+    })
+  }
+
+  if (event.data.type === "dereference") {
+    const res = await dereferenceDocs(event.data.docs)
+
+    self.postMessage({
+      type: "DEREFERENCE_RESULT",
+      data: res,
+    })
+  }
+})

+ 1 - 0
packages/hoppscotch-selfhost-web/vite.config.ts

@@ -27,6 +27,7 @@ export default defineConfig({
   define: {
     // For 'util' polyfill required by dep of '@apidevtools/swagger-parser'
     "process.env": {},
+    "process.platform": '"browser"',
   },
   server: {
     port: 3000,