Merge pull request #13640 from Budibase/fix/BUDI-8147

Typing improvements for REST integration - fixing no responses
This commit is contained in:
Michael Drury 2024-05-08 16:24:43 +01:00 committed by GitHub
commit c99e8103e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 22 deletions

View File

@ -26,13 +26,13 @@ import { parse } from "content-disposition"
import path from "path" import path from "path"
import { Builder as XmlBuilder } from "xml2js" import { Builder as XmlBuilder } from "xml2js"
const BodyTypes = { enum BodyType {
NONE: "none", NONE = "none",
FORM_DATA: "form", FORM_DATA = "form",
XML: "xml", XML = "xml",
ENCODED: "encoded", ENCODED = "encoded",
JSON: "json", JSON = "json",
TEXT: "text", TEXT = "text",
} }
const coreFields = { const coreFields = {
@ -54,7 +54,7 @@ const coreFields = {
}, },
bodyType: { bodyType: {
type: DatasourceFieldType.STRING, type: DatasourceFieldType.STRING,
enum: Object.values(BodyTypes), enum: Object.values(BodyType),
}, },
pagination: { pagination: {
type: DatasourceFieldType.OBJECT, type: DatasourceFieldType.OBJECT,
@ -131,7 +131,10 @@ class RestIntegration implements IntegrationBase {
} }
async parseResponse(response: any, pagination: PaginationConfig | null) { async parseResponse(response: any, pagination: PaginationConfig | null) {
let data, raw, headers, filename let data: any[] | string | undefined,
raw: string | undefined,
headers: Record<string, string> = {},
filename: string | undefined
const contentType = response.headers.get("content-type") || "" const contentType = response.headers.get("content-type") || ""
const contentDisposition = response.headers.get("content-disposition") || "" const contentDisposition = response.headers.get("content-disposition") || ""
@ -149,7 +152,7 @@ class RestIntegration implements IntegrationBase {
} else { } else {
if (response.status === 204) { if (response.status === 204) {
data = [] data = []
raw = [] raw = ""
} else if (contentType.includes("application/json")) { } else if (contentType.includes("application/json")) {
data = await response.json() data = await response.json()
raw = JSON.stringify(data) raw = JSON.stringify(data)
@ -162,16 +165,18 @@ class RestIntegration implements IntegrationBase {
raw = xmlResponse.rawXml raw = xmlResponse.rawXml
} else { } else {
data = await response.text() data = await response.text()
raw = data raw = data as string
} }
} }
} catch (err) { } catch (err) {
throw `Failed to parse response body: ${err}` throw `Failed to parse response body: ${err}`
} }
const size = formatBytes( let contentLength: string = response.headers.get("content-length")
response.headers.get("content-length") || Buffer.byteLength(raw, "utf8") if (!contentLength && raw) {
) contentLength = Buffer.byteLength(raw, "utf8").toString()
}
const size = formatBytes(contentLength || "0")
const time = `${Math.round(performance.now() - this.startTimeMs)}ms` const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
headers = response.headers.raw() headers = response.headers.raw()
for (let [key, value] of Object.entries(headers)) { for (let [key, value] of Object.entries(headers)) {
@ -255,7 +260,7 @@ class RestIntegration implements IntegrationBase {
if (!input.headers) { if (!input.headers) {
input.headers = {} input.headers = {}
} }
if (bodyType === BodyTypes.NONE) { if (bodyType === BodyType.NONE) {
return input return input
} }
let error, let error,
@ -283,11 +288,11 @@ class RestIntegration implements IntegrationBase {
} }
switch (bodyType) { switch (bodyType) {
case BodyTypes.TEXT: case BodyType.TEXT:
// content type defaults to plaintext // content type defaults to plaintext
input.body = string input.body = string
break break
case BodyTypes.ENCODED: { case BodyType.ENCODED: {
const params = new URLSearchParams() const params = new URLSearchParams()
for (let [key, value] of Object.entries(object)) { for (let [key, value] of Object.entries(object)) {
params.append(key, value as string) params.append(key, value as string)
@ -298,7 +303,7 @@ class RestIntegration implements IntegrationBase {
input.body = params input.body = params
break break
} }
case BodyTypes.FORM_DATA: { case BodyType.FORM_DATA: {
const form = new FormData() const form = new FormData()
for (let [key, value] of Object.entries(object)) { for (let [key, value] of Object.entries(object)) {
form.append(key, value) form.append(key, value)
@ -309,14 +314,14 @@ class RestIntegration implements IntegrationBase {
input.body = form input.body = form
break break
} }
case BodyTypes.XML: case BodyType.XML:
if (object != null && Object.keys(object).length) { if (object != null && Object.keys(object).length) {
string = new XmlBuilder().buildObject(object) string = new XmlBuilder().buildObject(object)
} }
input.body = string input.body = string
input.headers["Content-Type"] = "application/xml" input.headers["Content-Type"] = "application/xml"
break break
case BodyTypes.JSON: case BodyType.JSON:
// if JSON error, throw it // if JSON error, throw it
if (error) { if (error) {
throw "Invalid JSON for request body" throw "Invalid JSON for request body"

View File

@ -245,13 +245,13 @@ describe("REST Integration", () => {
expect(output.extra.headers["content-type"]).toEqual("application/xml") expect(output.extra.headers["content-type"]).toEqual("application/xml")
}) })
test.each(contentTypes)( test.each([...contentTypes, undefined])(
"should not throw an error on 204 no content", "should not throw an error on 204 no content",
async contentType => { async contentType => {
const input = buildInput(undefined, null, contentType, 204) const input = buildInput(undefined, null, contentType, 204)
const output = await config.integration.parseResponse(input) const output = await config.integration.parseResponse(input)
expect(output.data).toEqual([]) expect(output.data).toEqual([])
expect(output.extra.raw).toEqual([]) expect(output.extra.raw).toEqual("")
expect(output.info.code).toEqual(204) expect(output.info.code).toEqual(204)
expect(output.extra.headers["content-type"]).toEqual(contentType) expect(output.extra.headers["content-type"]).toEqual(contentType)
} }