Fix Insomnia text body imports (#507)

This commit is contained in:
Gregory Schier
2026-07-14 09:13:47 -07:00
committed by GitHub
parent c30f5b767b
commit e59ecce886
4 changed files with 188 additions and 89 deletions
+87
View File
@@ -1,3 +1,5 @@
/* oxlint-disable no-explicit-any */
export function isJSObject(obj: unknown) {
return Object.prototype.toString.call(obj) === "[object Object]";
}
@@ -13,6 +15,91 @@ export function convertId(id: string): string {
return `GENERATE_ID::${id}`;
}
export function importHttpBodyAndHeaders(obj: any) {
const { headers } = importHeaders(obj);
const { body, bodyType } = importHttpBody(obj.body);
const mimeType = typeof obj.body?.mimeType === "string" ? obj.body.mimeType.trim() : "";
if (
bodyType != null &&
mimeType !== "" &&
!headers.some((header: { name: string }) => header.name.toLowerCase() === "content-type")
) {
headers.push({ enabled: true, name: "Content-Type", value: mimeType });
}
return { body, bodyType, headers };
}
export function importHeaders(obj: any) {
const headers = (obj.headers ?? [])
.map((header: any) => ({
enabled: !header.disabled,
name: header.name ?? "",
value: header.value ?? "",
}))
.filter(({ name, value }: any) => name !== "" || value !== "");
return { headers } as const;
}
function importHttpBody(rawBody: any) {
const mimeType = typeof rawBody?.mimeType === "string" ? rawBody.mimeType.trim() : "";
const normalizedMimeType = mimeType.split(";", 1)[0]?.toLowerCase() ?? "";
if (normalizedMimeType === "application/octet-stream") {
return { bodyType: "binary", body: { filePath: rawBody.fileName ?? "" } };
}
if (normalizedMimeType === "application/x-www-form-urlencoded") {
return {
bodyType: "application/x-www-form-urlencoded",
body: {
form: (rawBody.params ?? []).map((parameter: any) => ({
enabled: !parameter.disabled,
name: parameter.name ?? "",
value: parameter.value ?? "",
})),
},
};
}
if (normalizedMimeType === "multipart/form-data") {
return {
bodyType: "multipart/form-data",
body: {
form: (rawBody.params ?? []).map((parameter: any) => ({
enabled: !parameter.disabled,
name: parameter.name ?? "",
value: parameter.value ?? "",
file: parameter.fileName ?? null,
})),
},
};
}
if (normalizedMimeType === "application/graphql") {
return { bodyType: "graphql", body: { text: rawBody.text ?? "" } };
}
if (normalizedMimeType === "application/json" || normalizedMimeType.endsWith("+json")) {
return { bodyType: "application/json", body: { text: rawBody.text ?? "" } };
}
if (
normalizedMimeType === "text/xml" ||
normalizedMimeType === "application/xml" ||
normalizedMimeType.endsWith("+xml")
) {
return { bodyType: "text/xml", body: { text: rawBody.text ?? "" } };
}
if (typeof rawBody?.text === "string") {
return { bodyType: "other", body: { text: rawBody.text } };
}
return { bodyType: null, body: {} };
}
export function deleteUndefinedAttrs<T>(obj: T): T {
if (Array.isArray(obj) && obj != null) {
return obj.map(deleteUndefinedAttrs) as T;
+2 -42
View File
@@ -1,6 +1,6 @@
/* oxlint-disable no-explicit-any */
import type { PartialImportResources } from "@yaakapp/api";
import { convertId, convertTemplateSyntax, isJSObject } from "./common";
import { convertId, convertTemplateSyntax, importHttpBodyAndHeaders, isJSObject } from "./common";
export function convertInsomniaV4(parsed: any) {
if (!Array.isArray(parsed.resources)) return null;
@@ -64,38 +64,6 @@ export function convertInsomniaV4(parsed: any) {
}
function importHttpRequest(r: any, workspaceId: string): PartialImportResources["httpRequests"][0] {
let bodyType: string | null = null;
let body = {};
if (r.body.mimeType === "application/octet-stream") {
bodyType = "binary";
body = { filePath: r.body.fileName ?? "" };
} else if (r.body?.mimeType === "application/x-www-form-urlencoded") {
bodyType = "application/x-www-form-urlencoded";
body = {
form: (r.body.params ?? []).map((p: any) => ({
enabled: !p.disabled,
name: p.name ?? "",
value: p.value ?? "",
})),
};
} else if (r.body?.mimeType === "multipart/form-data") {
bodyType = "multipart/form-data";
body = {
form: (r.body.params ?? []).map((p: any) => ({
enabled: !p.disabled,
name: p.name ?? "",
value: p.value ?? "",
file: p.fileName ?? null,
})),
};
} else if (r.body?.mimeType === "application/graphql") {
bodyType = "graphql";
body = { text: r.body.text ?? "" };
} else if (r.body?.mimeType === "application/json") {
bodyType = "application/json";
body = { text: r.body.text ?? "" };
}
let authenticationType: string | null = null;
let authentication = {};
if (r.authentication.type === "bearer") {
@@ -127,18 +95,10 @@ function importHttpRequest(r: any, workspaceId: string): PartialImportResources[
name: p.name ?? "",
value: p.value ?? "",
})),
body,
bodyType,
...importHttpBodyAndHeaders(r),
authentication,
authenticationType,
method: r.method,
headers: (r.headers ?? [])
.map((h: any) => ({
enabled: !h.disabled,
name: h.name ?? "",
value: h.value ?? "",
}))
.filter(({ name, value }: any) => name !== "" || value !== ""),
};
}
+8 -47
View File
@@ -1,6 +1,12 @@
/* oxlint-disable no-explicit-any */
import type { PartialImportResources } from "@yaakapp/api";
import { convertId, convertTemplateSyntax, isJSObject } from "./common";
import {
convertId,
convertTemplateSyntax,
importHeaders,
importHttpBodyAndHeaders,
isJSObject,
} from "./common";
export function convertInsomniaV5(parsed: any) {
// Assert parsed is object
@@ -82,38 +88,6 @@ function importHttpRequest(
const updated = r.meta?.modified ?? r.updated;
const sortKey = r.meta?.sortKey ?? r.sortKey;
let bodyType: string | null = null;
let body = {};
if (r.body?.mimeType === "application/octet-stream") {
bodyType = "binary";
body = { filePath: r.body.fileName ?? "" };
} else if (r.body?.mimeType === "application/x-www-form-urlencoded") {
bodyType = "application/x-www-form-urlencoded";
body = {
form: (r.body.params ?? []).map((p: any) => ({
enabled: !p.disabled,
name: p.name ?? "",
value: p.value ?? "",
})),
};
} else if (r.body?.mimeType === "multipart/form-data") {
bodyType = "multipart/form-data";
body = {
form: (r.body.params ?? []).map((p: any) => ({
enabled: !p.disabled,
name: p.name ?? "",
value: p.value ?? "",
file: p.fileName ?? null,
})),
};
} else if (r.body?.mimeType === "application/graphql") {
bodyType = "graphql";
body = { text: r.body.text ?? "" };
} else if (r.body?.mimeType === "application/json") {
bodyType = "application/json";
body = { text: r.body.text ?? "" };
}
return {
id: convertId(id),
workspaceId: convertId(workspaceId),
@@ -130,10 +104,8 @@ function importHttpRequest(
name: p.name ?? "",
value: p.value ?? "",
})),
body,
bodyType,
...importHttpBodyAndHeaders(r),
method: r.method,
...importHeaders(r),
...importAuthentication(r),
};
}
@@ -203,17 +175,6 @@ function importWebsocketRequest(
};
}
function importHeaders(obj: any) {
const headers = (obj.headers ?? [])
.map((h: any) => ({
enabled: !h.disabled,
name: h.name ?? "",
value: h.value ?? "",
}))
.filter(({ name, value }: any) => name !== "" || value !== "");
return { headers } as const;
}
function importAuthentication(obj: any) {
let authenticationType: string | null = null;
let authentication = {};
@@ -0,0 +1,91 @@
import { describe, expect, test } from "vite-plus/test";
import { importHttpBodyAndHeaders } from "../src/common";
describe("importHttpBodyAndHeaders", () => {
test("imports XML text using the native XML body type", () => {
const result = importHttpBodyAndHeaders({
body: {
mimeType: "application/soap+xml; charset=utf-8",
text: "<soap:Envelope />",
},
});
expect(result).toEqual({
bodyType: "text/xml",
body: { text: "<soap:Envelope />" },
headers: [
{
enabled: true,
name: "Content-Type",
value: "application/soap+xml; charset=utf-8",
},
],
});
});
test("imports vendor JSON using the native JSON body type", () => {
const result = importHttpBodyAndHeaders({
body: {
mimeType: "application/problem+json",
text: '{"message":"Nope"}',
},
});
expect(result.bodyType).toBe("application/json");
expect(result.body).toEqual({ text: '{"message":"Nope"}' });
});
test("imports unknown text using the other body type", () => {
const result = importHttpBodyAndHeaders({
body: {
mimeType: "application/yaml",
text: "message: hello",
},
});
expect(result).toEqual({
bodyType: "other",
body: { text: "message: hello" },
headers: [
{
enabled: true,
name: "Content-Type",
value: "application/yaml",
},
],
});
});
test("preserves an explicit content type instead of adding a duplicate", () => {
const result = importHttpBodyAndHeaders({
body: {
mimeType: "application/yaml",
text: "message: hello",
},
headers: [
{
name: "content-type",
value: "application/x-yaml",
},
],
});
expect(result.headers).toEqual([
{
enabled: true,
name: "content-type",
value: "application/x-yaml",
},
]);
});
test("imports text without inventing a content type", () => {
const result = importHttpBodyAndHeaders({ body: { text: "hello" } });
expect(result).toEqual({
bodyType: "other",
body: { text: "hello" },
headers: [],
});
});
});