diff --git a/packages/server/src/integrations/rest.ts b/packages/server/src/integrations/rest.ts index 5fae7b4e8f..1817f780d3 100644 --- a/packages/server/src/integrations/rest.ts +++ b/packages/server/src/integrations/rest.ts @@ -48,7 +48,7 @@ module RestModule { const { performance } = require("perf_hooks") const FormData = require("form-data") const { URLSearchParams } = require("url") - const xmlParser = require("xml2js").parseStringPromise + const { parseStringPromise: xmlParser, Builder: XmlBuilder } = require("xml2js") const SCHEMA: Integration = { docs: "https://github.com/node-fetch/node-fetch", @@ -185,7 +185,12 @@ module RestModule { } catch (err) { error = err } + if (!input.headers) { + input.headers = {} + } switch (bodyType) { + case BodyTypes.NONE: + break case BodyTypes.TEXT: // content type defaults to plaintext input.body = string @@ -205,8 +210,11 @@ module RestModule { input.body = form break case BodyTypes.XML: + if (object != null) { + string = (new XmlBuilder()).buildObject(object) + } input.body = string - input.headers["Content-Type"] = "text/xml" + input.headers["Content-Type"] = "application/xml" break default: case BodyTypes.JSON: diff --git a/packages/server/src/integrations/tests/rest.spec.js b/packages/server/src/integrations/tests/rest.spec.js index d2413b4af1..6cfa670622 100644 --- a/packages/server/src/integrations/tests/rest.spec.js +++ b/packages/server/src/integrations/tests/rest.spec.js @@ -111,6 +111,93 @@ describe("REST Integration", () => { }) }) + describe("request body", () => { + const input = { a: 1, b: 2 } + + it("should allow no body", () => { + const output = config.integration.addBody("none", null, {}) + expect(output.body).toBeUndefined() + expect(Object.keys(output.headers).length).toEqual(0) + }) + + it("should allow text body", () => { + const output = config.integration.addBody("text", "hello world", {}) + expect(output.body).toEqual("hello world") + // gets added by fetch + expect(Object.keys(output.headers).length).toEqual(0) + }) + + it("should allow form data", () => { + const FormData = require("form-data") + const output = config.integration.addBody("form", input, {}) + expect(output.body instanceof FormData).toEqual(true) + expect(output.body._valueLength).toEqual(2) + // gets added by fetch + expect(Object.keys(output.headers).length).toEqual(0) + }) + + it("should allow encoded form data", () => { + const { URLSearchParams } = require("url") + const output = config.integration.addBody("encoded", input, {}) + expect(output.body instanceof URLSearchParams).toEqual(true) + expect(output.body.toString()).toEqual("a=1&b=2") + // gets added by fetch + expect(Object.keys(output.headers).length).toEqual(0) + }) + + it("should allow JSON", () => { + const output = config.integration.addBody("json", input, {}) + expect(output.body).toEqual(JSON.stringify(input)) + expect(output.headers["Content-Type"]).toEqual("application/json") + }) + + it("should allow XML", () => { + const output = config.integration.addBody("xml", input, {}) + expect(output.body.includes("1")).toEqual(true) + expect(output.body.includes("2")).toEqual(true) + expect(output.headers["Content-Type"]).toEqual("application/xml") + }) + }) + + describe("response", () => { + function buildInput(json, text, header) { + return { + status: 200, + json: json ? async () => json : undefined, + text: text ? async () => text : undefined, + headers: { get: key => key === "content-length" ? 100 : header, raw: () => ({ "content-type": header }) } + } + } + + it("should be able to parse JSON response", async () => { + const input = buildInput({a: 1}, null, "application/json") + const output = await config.integration.parseResponse(input) + expect(output.data).toEqual({a: 1}) + expect(output.info.code).toEqual(200) + expect(output.info.size).toEqual("100B") + expect(output.extra.raw).toEqual(JSON.stringify({a: 1})) + expect(output.extra.headers["content-type"]).toEqual("application/json") + }) + + it("should be able to parse text response", async () => { + const text = "hello world" + const input = buildInput(null, text, "text/plain") + const output = await config.integration.parseResponse(input) + expect(output.data).toEqual(text) + expect(output.extra.raw).toEqual(text) + expect(output.extra.headers["content-type"]).toEqual("text/plain") + }) + + it("should be able to parse XML response", async () => { + const text = "12" + const input = buildInput(null, text, "application/xml") + const output = await config.integration.parseResponse(input) + expect(output.data).toEqual({a: "1", b: "2"}) + expect(output.extra.raw).toEqual(text) + expect(output.extra.headers["content-type"]).toEqual("application/xml") + }) + }) + describe("authentication", () => { const basicAuth = { _id: "c59c14bd1898a43baa08da68959b24686",