Skip to content

Instantly share code, notes, and snippets.

@joemaffei
Last active September 7, 2022 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joemaffei/e5e5079a739e398d00d489349b8e39f2 to your computer and use it in GitHub Desktop.
Save joemaffei/e5e5079a739e398d00d489349b8e39f2 to your computer and use it in GitHub Desktop.
Convert object to FormData
/**
* I started building this, then came across a more robust solution:
* {@link https://github.com/therealparmesh/object-to-formdata}
*/
import { isPlainObject } from "is-plain-object";
type Value = string | Blob | number | boolean | null | undefined | Date;
function convert<T extends Value>(value: T): string | Blob {
if (typeof value === "string" || value instanceof Blob) {
return value;
}
if (typeof value === "number" || typeof value === "boolean") {
return value.toString();
}
if (value instanceof Date) {
return value.toISOString();
}
return "";
}
export function buildFormData<T1>(input: T1) {
const formData = new FormData();
(function serialize<T2>(obj: T2, root?: string) {
for (const key in obj) {
const path = root
? Array.isArray(obj)
? `${root}[${key}]`
: `${root}.${key}`
: key;
if (Array.isArray(obj[key]) || isPlainObject(obj[key])) {
serialize(obj[key], path);
} else {
formData.append(path, convert(obj[key] as Value));
}
}
})(input);
return formData;
}
describe("helpers/formData", () => {
it("returns a FormData object", () => {
expect(buildFormData()).toBeInstanceOf(FormData);
});
it("works with strings", () => {
const formData = buildFormData({ first: "1st", second: "2nd" });
expect(formData.get("first")).toBe("1st");
expect(formData.get("second")).toBe("2nd");
});
it("works with blobs", () => {
const formData = buildFormData({ blob: new Blob() });
expect(formData.get("blob")).toBeInstanceOf(Blob);
});
it("stringifies numbers", () => {
const formData = buildFormData({ first: 1, second: 2 });
expect(formData.get("first")).toBe("1");
expect(formData.get("second")).toBe("2");
});
it("stringifies booleans", () => {
const formData = buildFormData({ first: true, second: false });
expect(formData.get("first")).toBe("true");
expect(formData.get("second")).toBe("false");
});
it("converts null and undefined to empty strings", () => {
const formData = buildFormData({ first: null, second: undefined });
expect(formData.get("first")).toBe("");
expect(formData.get("second")).toBe("");
});
it("converts dates to ISO strings", () => {
const dateString = "2000-01-01T00:00:00.000Z";
const date = new Date(dateString);
const formData = buildFormData({ date });
expect(formData.get("date")).toBe(dateString);
});
it("works on arrays of primitives", () => {
const formData = buildFormData({ arr: [1, 2] });
expect(formData.get("arr[0]")).toBe("1");
expect(formData.get("arr[1]")).toBe("2");
});
it("works on nested objects", () => {
const formData = buildFormData({ first: { a: 1 }, second: { b: 2 } });
expect(formData.get("first.a")).toBe("1");
expect(formData.get("second.b")).toBe("2");
});
it("works on arrays of objects", () => {
const formData = buildFormData({
arr: [
{ a: 1, b: 2 },
{ c: 3, d: 4 },
],
});
expect(formData.get("arr[0].a")).toBe("1");
expect(formData.get("arr[0].b")).toBe("2");
expect(formData.get("arr[1].c")).toBe("3");
expect(formData.get("arr[1].d")).toBe("4");
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment