feature/apiloader-ca-upload (#4533)

feat: add CA(.pem, .crt) upload in API Loader
This commit is contained in:
Ong Chung Yau
2025-06-06 02:29:52 +08:00
committed by GitHub
parent d134b66bd8
commit 5f7f83a5d2
@@ -1,8 +1,10 @@
import axios, { AxiosRequestConfig } from 'axios'
import { omit } from 'lodash'
import { Document } from '@langchain/core/documents' import { Document } from '@langchain/core/documents'
import { TextSplitter } from 'langchain/text_splitter' import axios, { AxiosRequestConfig } from 'axios'
import * as https from 'https'
import { BaseDocumentLoader } from 'langchain/document_loaders/base' import { BaseDocumentLoader } from 'langchain/document_loaders/base'
import { TextSplitter } from 'langchain/text_splitter'
import { omit } from 'lodash'
import { getFileFromStorage } from '../../../src'
import { ICommonObject, IDocument, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' import { ICommonObject, IDocument, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
import { handleEscapeCharacters } from '../../../src/utils' import { handleEscapeCharacters } from '../../../src/utils'
@@ -21,7 +23,7 @@ class API_DocumentLoaders implements INode {
constructor() { constructor() {
this.label = 'API Loader' this.label = 'API Loader'
this.name = 'apiLoader' this.name = 'apiLoader'
this.version = 2.0 this.version = 2.1
this.type = 'Document' this.type = 'Document'
this.icon = 'api.svg' this.icon = 'api.svg'
this.category = 'Document Loaders' this.category = 'Document Loaders'
@@ -61,6 +63,15 @@ class API_DocumentLoaders implements INode {
additionalParams: true, additionalParams: true,
optional: true optional: true
}, },
{
label: 'SSL Certificate',
description: 'Please upload a SSL certificate file in either .pem or .crt',
name: 'caFile',
type: 'file',
fileType: '.pem, .crt',
additionalParams: true,
optional: true
},
{ {
label: 'Body', label: 'Body',
name: 'body', name: 'body',
@@ -105,8 +116,10 @@ class API_DocumentLoaders implements INode {
} }
] ]
} }
async init(nodeData: INodeData): Promise<any> {
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
const headers = nodeData.inputs?.headers as string const headers = nodeData.inputs?.headers as string
const caFileBase64 = nodeData.inputs?.caFile as string
const url = nodeData.inputs?.url as string const url = nodeData.inputs?.url as string
const body = nodeData.inputs?.body as string const body = nodeData.inputs?.body as string
const method = nodeData.inputs?.method as string const method = nodeData.inputs?.method as string
@@ -120,22 +133,37 @@ class API_DocumentLoaders implements INode {
omitMetadataKeys = _omitMetadataKeys.split(',').map((key) => key.trim()) omitMetadataKeys = _omitMetadataKeys.split(',').map((key) => key.trim())
} }
const options: ApiLoaderParams = { const apiLoaderParam: ApiLoaderParams = {
url, url,
method method
} }
if (headers) { if (headers) {
const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(headers) const parsedHeaders = typeof headers === 'object' ? headers : JSON.parse(headers)
options.headers = parsedHeaders apiLoaderParam.headers = parsedHeaders
}
if (caFileBase64.startsWith('FILE-STORAGE::')) {
let file = caFileBase64.replace('FILE-STORAGE::', '')
file = file.replace('[', '')
file = file.replace(']', '')
const orgId = options.orgId
const chatflowid = options.chatflowid
const fileData = await getFileFromStorage(file, orgId, chatflowid)
apiLoaderParam.ca = fileData.toString()
} else {
const splitDataURI = caFileBase64.split(',')
splitDataURI.pop()
const bf = Buffer.from(splitDataURI.pop() || '', 'base64')
apiLoaderParam.ca = bf.toString('utf-8')
} }
if (body) { if (body) {
const parsedBody = typeof body === 'object' ? body : JSON.parse(body) const parsedBody = typeof body === 'object' ? body : JSON.parse(body)
options.body = parsedBody apiLoaderParam.body = parsedBody
} }
const loader = new ApiLoader(options) const loader = new ApiLoader(apiLoaderParam)
let docs: IDocument[] = [] let docs: IDocument[] = []
@@ -195,6 +223,7 @@ interface ApiLoaderParams {
method: string method: string
headers?: ICommonObject headers?: ICommonObject
body?: ICommonObject body?: ICommonObject
ca?: string
} }
class ApiLoader extends BaseDocumentLoader { class ApiLoader extends BaseDocumentLoader {
@@ -206,28 +235,36 @@ class ApiLoader extends BaseDocumentLoader {
public readonly method: string public readonly method: string
constructor({ url, headers, body, method }: ApiLoaderParams) { public readonly ca?: string
constructor({ url, headers, body, method, ca }: ApiLoaderParams) {
super() super()
this.url = url this.url = url
this.headers = headers this.headers = headers
this.body = body this.body = body
this.method = method this.method = method
this.ca = ca
} }
public async load(): Promise<IDocument[]> { public async load(): Promise<IDocument[]> {
if (this.method === 'POST') { if (this.method === 'POST') {
return this.executePostRequest(this.url, this.headers, this.body) return this.executePostRequest(this.url, this.headers, this.body, this.ca)
} else { } else {
return this.executeGetRequest(this.url, this.headers) return this.executeGetRequest(this.url, this.headers, this.ca)
} }
} }
protected async executeGetRequest(url: string, headers?: ICommonObject): Promise<IDocument[]> { protected async executeGetRequest(url: string, headers?: ICommonObject, ca?: string): Promise<IDocument[]> {
try { try {
const config: AxiosRequestConfig = {} const config: AxiosRequestConfig = {}
if (headers) { if (headers) {
config.headers = headers config.headers = headers
} }
if (ca) {
config.httpsAgent = new https.Agent({
ca: ca
})
}
const response = await axios.get(url, config) const response = await axios.get(url, config)
const responseJsonString = JSON.stringify(response.data, null, 2) const responseJsonString = JSON.stringify(response.data, null, 2)
const doc = new Document({ const doc = new Document({
@@ -242,12 +279,17 @@ class ApiLoader extends BaseDocumentLoader {
} }
} }
protected async executePostRequest(url: string, headers?: ICommonObject, body?: ICommonObject): Promise<IDocument[]> { protected async executePostRequest(url: string, headers?: ICommonObject, body?: ICommonObject, ca?: string): Promise<IDocument[]> {
try { try {
const config: AxiosRequestConfig = {} const config: AxiosRequestConfig = {}
if (headers) { if (headers) {
config.headers = headers config.headers = headers
} }
if (ca) {
config.httpsAgent = new https.Agent({
ca: ca
})
}
const response = await axios.post(url, body ?? {}, config) const response = await axios.post(url, body ?? {}, config)
const responseJsonString = JSON.stringify(response.data, null, 2) const responseJsonString = JSON.stringify(response.data, null, 2)
const doc = new Document({ const doc = new Document({