2021-06-24 19:17:26 +02:00
|
|
|
import {
|
|
|
|
Integration,
|
|
|
|
DatasourceFieldTypes,
|
|
|
|
QueryTypes,
|
2021-06-27 00:09:46 +02:00
|
|
|
} from "../definitions/datasource"
|
2021-11-10 20:35:09 +01:00
|
|
|
import { IntegrationBase } from "./base/IntegrationBase"
|
2021-06-24 19:16:48 +02:00
|
|
|
|
2021-12-02 18:53:14 +01:00
|
|
|
const BodyTypes = {
|
|
|
|
NONE: "none",
|
|
|
|
FORM_DATA: "form",
|
|
|
|
ENCODED: "encoded",
|
|
|
|
JSON: "json",
|
|
|
|
TEXT: "text",
|
|
|
|
}
|
|
|
|
|
2021-12-07 23:33:26 +01:00
|
|
|
enum AuthType {
|
|
|
|
BASIC = "basic",
|
|
|
|
BEARER = "bearer"
|
|
|
|
}
|
|
|
|
|
|
|
|
interface AuthConfig {
|
|
|
|
id: string
|
|
|
|
type: AuthType
|
|
|
|
config: BasicAuthConfig | BearerAuthConfig
|
|
|
|
}
|
2021-12-08 11:52:08 +01:00
|
|
|
|
2021-12-07 23:33:26 +01:00
|
|
|
interface BasicAuthConfig {
|
|
|
|
username: string,
|
|
|
|
password: string,
|
|
|
|
}
|
|
|
|
|
|
|
|
interface BearerAuthConfig {
|
|
|
|
token: string,
|
|
|
|
}
|
|
|
|
|
2021-12-02 18:53:14 +01:00
|
|
|
const coreFields = {
|
|
|
|
path: {
|
|
|
|
type: DatasourceFieldTypes.STRING,
|
|
|
|
display: "URL",
|
|
|
|
},
|
|
|
|
queryString: {
|
|
|
|
type: DatasourceFieldTypes.STRING,
|
|
|
|
},
|
|
|
|
headers: {
|
|
|
|
type: DatasourceFieldTypes.OBJECT,
|
|
|
|
},
|
|
|
|
enabledHeaders: {
|
|
|
|
type: DatasourceFieldTypes.OBJECT,
|
|
|
|
},
|
|
|
|
requestBody: {
|
|
|
|
type: DatasourceFieldTypes.JSON,
|
|
|
|
},
|
|
|
|
bodyType: {
|
|
|
|
type: DatasourceFieldTypes.STRING,
|
2021-12-03 19:39:05 +01:00
|
|
|
enum: Object.values(BodyTypes),
|
2021-12-02 18:53:14 +01:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-06-24 19:16:48 +02:00
|
|
|
module RestModule {
|
|
|
|
const fetch = require("node-fetch")
|
2021-12-06 19:23:18 +01:00
|
|
|
const { formatBytes } = require("../utilities")
|
|
|
|
const { performance } = require("perf_hooks")
|
2021-06-24 19:16:48 +02:00
|
|
|
|
|
|
|
interface RestConfig {
|
2021-06-24 19:17:26 +02:00
|
|
|
url: string
|
2021-06-24 19:16:48 +02:00
|
|
|
defaultHeaders: {
|
2021-06-24 19:17:26 +02:00
|
|
|
[key: string]: any
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
2021-12-07 23:33:26 +01:00
|
|
|
authConfigs: AuthConfig[]
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
interface Request {
|
|
|
|
path: string
|
|
|
|
queryString?: string
|
|
|
|
headers?: string
|
|
|
|
json?: any
|
|
|
|
}
|
|
|
|
|
2021-06-24 19:16:48 +02:00
|
|
|
const SCHEMA: Integration = {
|
|
|
|
docs: "https://github.com/node-fetch/node-fetch",
|
|
|
|
description:
|
2021-11-30 19:11:29 +01:00
|
|
|
"With the REST API datasource, you can connect, query and pull data from multiple REST APIs. You can then use the retrieved data to build apps.",
|
2021-06-24 19:16:48 +02:00
|
|
|
friendlyName: "REST API",
|
|
|
|
datasource: {
|
|
|
|
url: {
|
|
|
|
type: DatasourceFieldTypes.STRING,
|
2021-11-30 17:21:16 +01:00
|
|
|
default: "",
|
|
|
|
required: false,
|
|
|
|
deprecated: true,
|
2021-06-24 19:16:48 +02:00
|
|
|
},
|
|
|
|
defaultHeaders: {
|
|
|
|
type: DatasourceFieldTypes.OBJECT,
|
|
|
|
required: false,
|
|
|
|
default: {},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
query: {
|
|
|
|
create: {
|
|
|
|
readable: true,
|
|
|
|
displayName: "POST",
|
|
|
|
type: QueryTypes.FIELDS,
|
2021-12-02 18:53:14 +01:00
|
|
|
fields: coreFields,
|
2021-06-24 19:16:48 +02:00
|
|
|
},
|
|
|
|
read: {
|
|
|
|
displayName: "GET",
|
|
|
|
readable: true,
|
|
|
|
type: QueryTypes.FIELDS,
|
2021-12-02 18:53:14 +01:00
|
|
|
fields: coreFields,
|
2021-06-24 19:16:48 +02:00
|
|
|
},
|
|
|
|
update: {
|
|
|
|
displayName: "PUT",
|
|
|
|
readable: true,
|
|
|
|
type: QueryTypes.FIELDS,
|
2021-12-02 18:53:14 +01:00
|
|
|
fields: coreFields,
|
2021-06-24 19:16:48 +02:00
|
|
|
},
|
2021-08-30 22:55:12 +02:00
|
|
|
patch: {
|
|
|
|
displayName: "PATCH",
|
|
|
|
readable: true,
|
|
|
|
type: QueryTypes.FIELDS,
|
2021-12-02 18:53:14 +01:00
|
|
|
fields: coreFields,
|
2021-08-30 22:55:12 +02:00
|
|
|
},
|
2021-06-24 19:16:48 +02:00
|
|
|
delete: {
|
|
|
|
displayName: "DELETE",
|
|
|
|
type: QueryTypes.FIELDS,
|
2021-12-02 18:53:14 +01:00
|
|
|
fields: coreFields,
|
2021-06-24 19:16:48 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-11-10 20:35:09 +01:00
|
|
|
class RestIntegration implements IntegrationBase {
|
2021-06-24 19:16:48 +02:00
|
|
|
private config: RestConfig
|
|
|
|
private headers: {
|
|
|
|
[key: string]: string
|
|
|
|
} = {}
|
2021-12-06 19:23:18 +01:00
|
|
|
private startTimeMs: number = performance.now()
|
2021-06-24 19:16:48 +02:00
|
|
|
|
|
|
|
constructor(config: RestConfig) {
|
|
|
|
this.config = config
|
|
|
|
}
|
|
|
|
|
|
|
|
async parseResponse(response: any) {
|
2021-12-06 19:35:44 +01:00
|
|
|
let data, raw
|
2021-11-03 14:12:20 +01:00
|
|
|
const contentType = response.headers.get("content-type")
|
|
|
|
if (contentType && contentType.indexOf("application/json") !== -1) {
|
2021-12-06 19:23:18 +01:00
|
|
|
data = await response.json()
|
2021-12-06 19:35:44 +01:00
|
|
|
raw = JSON.stringify(data)
|
2021-11-03 14:12:20 +01:00
|
|
|
} else {
|
2021-12-06 19:23:18 +01:00
|
|
|
data = await response.text()
|
2021-12-06 19:35:44 +01:00
|
|
|
raw = data
|
2021-12-06 19:23:18 +01:00
|
|
|
}
|
|
|
|
const size = formatBytes(response.headers.get("content-length") || 0)
|
|
|
|
const time = `${Math.round(performance.now() - this.startTimeMs)}ms`
|
|
|
|
return {
|
|
|
|
data,
|
|
|
|
info: {
|
|
|
|
code: response.status,
|
|
|
|
size,
|
|
|
|
time,
|
|
|
|
},
|
2021-12-06 19:35:44 +01:00
|
|
|
raw,
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-05 12:20:09 +02:00
|
|
|
getUrl(path: string, queryString: string): string {
|
2021-11-30 18:56:15 +01:00
|
|
|
const main = `${path}?${queryString}`
|
|
|
|
if (!this.config.url) {
|
|
|
|
return main
|
|
|
|
} else {
|
|
|
|
return `${this.config.url}/${main}`
|
|
|
|
}
|
2021-10-05 12:20:09 +02:00
|
|
|
}
|
|
|
|
|
2021-12-07 23:33:26 +01:00
|
|
|
processAuth(authConfigId: string) {
|
2021-12-08 11:52:08 +01:00
|
|
|
if (!this.config.authConfigs || !authConfigId) {
|
2021-12-07 23:33:26 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
const authConfig = this.config.authConfigs.filter(authConfig => authConfig.id === authConfigId)[0]
|
|
|
|
let config
|
|
|
|
switch (authConfig.type) {
|
|
|
|
case AuthType.BASIC:
|
|
|
|
config = authConfig.config as BasicAuthConfig
|
|
|
|
this.headers.Authorization = `Basic ${Buffer.from(`${config.username}:${config.password}`).toString("base64")}`
|
|
|
|
break
|
|
|
|
case AuthType.BEARER:
|
|
|
|
config = authConfig.config as BearerAuthConfig
|
|
|
|
this.headers.Authorization = `Bearer ${config.token}`
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async _req({ path = "", queryString = "", headers = {}, json = {}, method = "GET", authConfigId = "" }) {
|
2021-06-24 19:16:48 +02:00
|
|
|
this.headers = {
|
|
|
|
...this.config.defaultHeaders,
|
|
|
|
...headers,
|
|
|
|
}
|
|
|
|
|
2021-12-07 23:33:26 +01:00
|
|
|
this.processAuth(authConfigId)
|
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
const input: any = { method, headers: this.headers }
|
|
|
|
if (json && typeof json === "object" && Object.keys(json).length > 0) {
|
|
|
|
input.body = JSON.stringify(json)
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
this.startTimeMs = performance.now()
|
|
|
|
const response = await fetch(this.getUrl(path, queryString), input)
|
2021-06-24 19:16:48 +02:00
|
|
|
return await this.parseResponse(response)
|
|
|
|
}
|
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
async create(opts: Request) {
|
|
|
|
return this._req({ ...opts, method: "POST" })
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
async read(opts: Request) {
|
|
|
|
return this._req({ ...opts, method: "GET" })
|
2021-08-30 22:55:12 +02:00
|
|
|
}
|
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
async update(opts: Request) {
|
|
|
|
return this._req({ ...opts, method: "PUT" })
|
|
|
|
}
|
2021-06-24 19:16:48 +02:00
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
async patch(opts: Request) {
|
|
|
|
return this._req({ ...opts, method: "PATCH" })
|
|
|
|
}
|
2021-06-24 19:16:48 +02:00
|
|
|
|
2021-12-06 19:23:18 +01:00
|
|
|
async delete(opts: Request) {
|
|
|
|
return this._req({ ...opts, method: "DELETE" })
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
schema: SCHEMA,
|
|
|
|
integration: RestIntegration,
|
2021-12-07 23:33:26 +01:00
|
|
|
AuthType
|
2021-06-24 19:16:48 +02:00
|
|
|
}
|
|
|
|
}
|