refactor: port postman and insomnia importers
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import HoppRESTCollImporter from "./hopp"
|
||||
import OpenAPIImporter from "./openapi"
|
||||
import PostmanImporter from "./postman"
|
||||
import InsomniaImporter from "./insomnia"
|
||||
|
||||
export const RESTCollectionImporters = [
|
||||
HoppRESTCollImporter,
|
||||
OpenAPIImporter,
|
||||
PostmanImporter,
|
||||
InsomniaImporter,
|
||||
] as const
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { step } from "../steps"
|
||||
import { parsePostmanCollection } from "./postman"
|
||||
import { defineImporter, IMPORTER_INVALID_FILE_FORMAT } from "."
|
||||
import { parseInsomniaCollection } from "~/helpers/utils/parseInsomniaCollection"
|
||||
import { Collection } from "~/newstore/collections"
|
||||
|
||||
// This Importer definition is less than ideal,
|
||||
// would love an attempt at refactoring this
|
||||
|
||||
export default defineImporter({
|
||||
name: "Insomnia Collection",
|
||||
steps: [
|
||||
step({
|
||||
stepName: "FILE_OR_URL_IMPORT",
|
||||
metadata: {
|
||||
acceptedFileTypes: ".json",
|
||||
},
|
||||
}),
|
||||
] as const,
|
||||
importer: ([fileContent]) => {
|
||||
try {
|
||||
let collections = parseInsomniaCollection(fileContent)
|
||||
const content = JSON.stringify(collections)
|
||||
|
||||
if (collections[0]) {
|
||||
const [name, folders, requests] = Object.keys(collections[0])
|
||||
if (
|
||||
name === "name" &&
|
||||
folders === "folders" &&
|
||||
requests === "requests"
|
||||
) {
|
||||
return TE.right(collections as Collection<HoppRESTRequest>[])
|
||||
}
|
||||
|
||||
return TE.left(IMPORTER_INVALID_FILE_FORMAT)
|
||||
} else if (
|
||||
collections.info &&
|
||||
collections.info.schema.includes("v2.1.0")
|
||||
) {
|
||||
// replace the variables, postman uses {{var}}, Hoppscotch uses <<var>>
|
||||
collections = JSON.parse(content.replaceAll(/{{([a-z]+)}}/gi, "<<$1>>"))
|
||||
collections = [parsePostmanCollection(collections)]
|
||||
|
||||
return TE.right(collections as Collection<HoppRESTRequest>[])
|
||||
} else {
|
||||
return TE.left(IMPORTER_INVALID_FILE_FORMAT)
|
||||
}
|
||||
} catch (_e) {
|
||||
return TE.left(IMPORTER_INVALID_FILE_FORMAT)
|
||||
}
|
||||
},
|
||||
})
|
||||
203
packages/hoppscotch-app/helpers/import-export/import/postman.ts
Normal file
203
packages/hoppscotch-app/helpers/import-export/import/postman.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
import { HoppRESTRequest, translateToNewRequest } from "@hoppscotch/data"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { step } from "../steps"
|
||||
import { defineImporter, IMPORTER_INVALID_FILE_FORMAT } from "."
|
||||
import { Collection, makeCollection } from "~/newstore/collections"
|
||||
|
||||
// TODO: I don't even know what is going on here :/
|
||||
type PostmanCollection = {
|
||||
info?: {
|
||||
name: string
|
||||
}
|
||||
name: string
|
||||
item: {
|
||||
name: string
|
||||
request: any
|
||||
item?: any
|
||||
}[]
|
||||
folders?: any
|
||||
}
|
||||
|
||||
const hasFolder = (item: { item?: any }) => {
|
||||
return Object.prototype.hasOwnProperty.call(item, "item")
|
||||
}
|
||||
|
||||
export const parsePostmanCollection = ({
|
||||
info,
|
||||
name,
|
||||
item,
|
||||
}: PostmanCollection) => {
|
||||
const hoppscotchCollection: Collection<HoppRESTRequest> = makeCollection({
|
||||
name: "",
|
||||
folders: [],
|
||||
requests: [],
|
||||
})
|
||||
|
||||
hoppscotchCollection.name = info ? info.name : name
|
||||
|
||||
if (item && item.length > 0) {
|
||||
for (const collectionItem of item) {
|
||||
if (collectionItem.request) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(hoppscotchCollection, "folders")
|
||||
) {
|
||||
hoppscotchCollection.name = info ? info.name : name
|
||||
hoppscotchCollection.requests.push(
|
||||
parsePostmanRequest(collectionItem)
|
||||
)
|
||||
} else {
|
||||
hoppscotchCollection.name = name || ""
|
||||
hoppscotchCollection.requests.push(
|
||||
parsePostmanRequest(collectionItem)
|
||||
)
|
||||
}
|
||||
} else if (hasFolder(collectionItem)) {
|
||||
hoppscotchCollection.folders.push(
|
||||
parsePostmanCollection(collectionItem as any)
|
||||
)
|
||||
} else {
|
||||
hoppscotchCollection.requests.push(parsePostmanRequest(collectionItem))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hoppscotchCollection
|
||||
}
|
||||
|
||||
// TODO: Rewrite
|
||||
const parsePostmanRequest = ({
|
||||
name,
|
||||
request,
|
||||
}: {
|
||||
name: string
|
||||
request: any
|
||||
}) => {
|
||||
const pwRequest = {
|
||||
url: "",
|
||||
path: "",
|
||||
method: "",
|
||||
auth: "",
|
||||
httpUser: "",
|
||||
httpPassword: "",
|
||||
passwordFieldType: "password",
|
||||
bearerToken: "",
|
||||
headers: [] as { name?: string; type?: string }[],
|
||||
params: [] as { disabled?: boolean }[],
|
||||
bodyParams: [] as { type?: string }[],
|
||||
body: {
|
||||
body: "",
|
||||
contentType: "application/json",
|
||||
},
|
||||
rawParams: "",
|
||||
rawInput: false,
|
||||
contentType: "",
|
||||
requestType: "",
|
||||
name: "",
|
||||
}
|
||||
|
||||
pwRequest.name = name
|
||||
if (request.url) {
|
||||
const requestObjectUrl = request.url.raw.match(
|
||||
/^(.+:\/\/[^/]+|{[^/]+})(\/[^?]+|).*$/
|
||||
)
|
||||
if (requestObjectUrl) {
|
||||
pwRequest.url = requestObjectUrl[1]
|
||||
pwRequest.path = requestObjectUrl[2] ? requestObjectUrl[2] : ""
|
||||
} else {
|
||||
pwRequest.url = request.url.raw
|
||||
}
|
||||
}
|
||||
|
||||
pwRequest.method = request.method
|
||||
const itemAuth = request.auth ? request.auth : ""
|
||||
const authType = itemAuth ? itemAuth.type : ""
|
||||
|
||||
try {
|
||||
if (authType === "basic") {
|
||||
pwRequest.auth = "Basic Auth"
|
||||
pwRequest.httpUser =
|
||||
itemAuth.basic[0].key === "username"
|
||||
? itemAuth.basic[0].value
|
||||
: itemAuth.basic[1].value
|
||||
pwRequest.httpPassword =
|
||||
itemAuth.basic[0].key === "password"
|
||||
? itemAuth.basic[0].value
|
||||
: itemAuth.basic[1].value
|
||||
} else if (authType === "oauth2") {
|
||||
pwRequest.auth = "OAuth 2.0"
|
||||
pwRequest.bearerToken =
|
||||
itemAuth.oauth2[0].key === "accessToken"
|
||||
? itemAuth.oauth2[0].value
|
||||
: itemAuth.oauth2[1].value
|
||||
} else if (authType === "bearer") {
|
||||
pwRequest.auth = "Bearer Token"
|
||||
pwRequest.bearerToken = itemAuth.bearer[0].value
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
const requestObjectHeaders = request.header
|
||||
if (requestObjectHeaders) {
|
||||
pwRequest.headers = requestObjectHeaders
|
||||
for (const header of pwRequest.headers) {
|
||||
delete header.name
|
||||
delete header.type
|
||||
}
|
||||
}
|
||||
if (request.url) {
|
||||
const requestObjectParams = request.url.query
|
||||
if (requestObjectParams) {
|
||||
pwRequest.params = requestObjectParams
|
||||
for (const param of pwRequest.params) {
|
||||
delete param.disabled
|
||||
}
|
||||
}
|
||||
}
|
||||
if (request.body) {
|
||||
if (request.body.mode === "urlencoded") {
|
||||
const params = request.body.urlencoded
|
||||
pwRequest.bodyParams = params || []
|
||||
for (const param of pwRequest.bodyParams) {
|
||||
delete param.type
|
||||
}
|
||||
} else if (request.body.mode === "raw") {
|
||||
pwRequest.rawInput = true
|
||||
pwRequest.rawParams = request.body.raw
|
||||
try {
|
||||
const body = JSON.parse(request.body.raw)
|
||||
pwRequest.body.body = JSON.stringify(body, null, 2)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
return translateToNewRequest(pwRequest)
|
||||
}
|
||||
|
||||
const safeParseJSON = (str: string) => O.tryCatch(() => JSON.parse(str))
|
||||
|
||||
export default defineImporter({
|
||||
name: "Postman Collection",
|
||||
steps: [
|
||||
step({
|
||||
stepName: "FILE_OR_URL_IMPORT",
|
||||
metadata: {
|
||||
acceptedFileTypes: ".json",
|
||||
},
|
||||
}),
|
||||
] as const,
|
||||
importer: ([fileContent]) =>
|
||||
pipe(
|
||||
// Parse to JSON
|
||||
fileContent,
|
||||
safeParseJSON,
|
||||
|
||||
// Parse To Postman Collection
|
||||
O.chain((data) => O.tryCatch(() => parsePostmanCollection(data))),
|
||||
|
||||
// Convert Option to Task Either
|
||||
TE.fromOption(() => IMPORTER_INVALID_FILE_FORMAT)
|
||||
),
|
||||
})
|
||||
Reference in New Issue
Block a user