API-Explorer-II/server/services/OBPClientService.ts

247 lines
7.5 KiB
TypeScript
Raw Normal View History

2024-05-14 11:41:52 +00:00
/*
* Open Bank Project - API Explorer II
* Copyright (C) 2023-2024, TESOBE GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Email: contact@tesobe.com
* TESOBE GmbH
* Osloerstrasse 16/17
* Berlin 13359, Germany
*
* This product includes software developed at
* TESOBE (http://www.tesobe.com/)
*
*/
2023-05-03 17:17:01 +00:00
import { Service } from 'typedi'
import { DEFAULT_OBP_API_VERSION } from '../../shared-constants'
2025-12-01 10:28:40 +00:00
// Custom error class to preserve HTTP status codes
class OBPAPIError extends Error {
status: number
constructor(status: number, message: string) {
super(message)
this.status = status
this.name = 'OBPAPIError'
}
}
2025-12-01 10:28:40 +00:00
// OAuth2 Bearer token configuration
interface OAuth2Config {
accessToken: string
tokenType: string
}
// API Client configuration for OAuth2
interface APIClientConfig {
baseUri: string
version: string
oauth2?: OAuth2Config
}
2023-05-03 17:17:01 +00:00
@Service()
2025-03-12 12:10:30 +00:00
/**
* OBPClientService provides methods for interacting with the Open Bank Project API.
2025-12-01 10:28:40 +00:00
*
* This service handles API communication with OBP using OAuth2 Bearer token authentication,
* making HTTP requests (GET, POST, PUT, DELETE).
*
2025-03-12 12:10:30 +00:00
* @class OBPClientService
2025-12-01 10:28:40 +00:00
*
2025-03-12 12:10:30 +00:00
* @property {APIClientConfig} clientConfig - API client configuration
2025-12-01 10:28:40 +00:00
*
2025-03-12 12:10:30 +00:00
* @example
* const obpService = new OBPClientService();
2025-12-01 10:28:40 +00:00
* const response = await obpService.get('/obp/v5.1.0/banks', sessionConfig);
2025-03-12 12:10:30 +00:00
*/
2023-05-03 17:17:01 +00:00
export default class OBPClientService {
private clientConfig: APIClientConfig
2025-12-01 10:28:40 +00:00
2023-05-03 17:17:01 +00:00
constructor() {
if (!process.env.VITE_OBP_API_HOST) throw new Error('VITE_OBP_API_HOST is not set')
2025-12-01 10:28:40 +00:00
2023-05-03 17:17:01 +00:00
this.clientConfig = {
baseUri: process.env.VITE_OBP_API_HOST!,
2025-12-01 10:28:40 +00:00
version: process.env.VITE_OBP_API_VERSION ?? DEFAULT_OBP_API_VERSION
2023-05-03 17:17:01 +00:00
}
}
2023-06-05 15:32:25 +00:00
async get(path: string, clientConfig: any): Promise<any> {
2023-06-05 15:39:20 +00:00
const config = this.getSessionConfig(clientConfig)
2025-12-01 10:28:40 +00:00
if (!config.oauth2?.accessToken) {
throw new Error('OAuth2 access token not found. Please authenticate first.')
}
return await this.getWithBearer(path, config.oauth2.accessToken)
2023-05-03 17:17:01 +00:00
}
2025-12-01 10:28:40 +00:00
2023-06-05 15:32:25 +00:00
async create(path: string, body: any, clientConfig: any): Promise<any> {
2023-06-05 15:39:20 +00:00
const config = this.getSessionConfig(clientConfig)
2025-12-01 10:28:40 +00:00
if (!config.oauth2?.accessToken) {
throw new Error('OAuth2 access token not found. Please authenticate first.')
}
return await this.createWithBearer(path, body, config.oauth2.accessToken)
2023-05-03 17:17:01 +00:00
}
2025-12-01 10:28:40 +00:00
2023-06-05 15:32:25 +00:00
async update(path: string, body: any, clientConfig: any): Promise<any> {
2023-06-05 15:39:20 +00:00
const config = this.getSessionConfig(clientConfig)
2025-12-01 10:28:40 +00:00
if (!config.oauth2?.accessToken) {
throw new Error('OAuth2 access token not found. Please authenticate first.')
}
return await this.updateWithBearer(path, body, config.oauth2.accessToken)
2023-05-03 17:17:01 +00:00
}
2025-12-01 10:28:40 +00:00
2023-06-05 15:32:25 +00:00
async discard(path: string, clientConfig: any): Promise<any> {
2023-06-05 15:39:20 +00:00
const config = this.getSessionConfig(clientConfig)
2025-12-01 10:28:40 +00:00
if (!config.oauth2?.accessToken) {
throw new Error('OAuth2 access token not found. Please authenticate first.')
}
return await this.discardWithBearer(path, config.oauth2.accessToken)
2023-06-05 15:39:20 +00:00
}
2025-03-12 12:10:30 +00:00
private getSessionConfig(clientConfig: APIClientConfig): APIClientConfig {
2023-06-05 15:39:20 +00:00
return clientConfig || this.clientConfig
2023-05-03 17:17:01 +00:00
}
getOBPVersion(): string {
return this.clientConfig.version
}
2023-06-05 15:32:25 +00:00
2025-03-07 16:21:10 +00:00
getOBPClientConfig(): APIClientConfig {
2023-06-05 15:32:25 +00:00
return this.clientConfig
}
2025-03-12 12:10:30 +00:00
/**
2025-12-01 10:28:40 +00:00
* Make a GET request with OAuth2 Bearer token authentication
*
* @param path - The API endpoint path (e.g., /obp/v5.1.0/banks)
* @param accessToken - OAuth2 access token
* @returns Response data from the API
2025-03-12 12:10:30 +00:00
*/
2025-12-01 10:28:40 +00:00
private async getWithBearer(path: string, accessToken: string): Promise<any> {
const url = `${this.clientConfig.baseUri}${path}`
console.log('OBPClientService: GET request with Bearer token to:', url)
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
})
if (!response.ok) {
const errorText = await response.text()
console.error('OBPClientService: GET request failed:', response.status, errorText)
throw new OBPAPIError(response.status, errorText)
2025-03-12 12:10:30 +00:00
}
2025-12-01 10:28:40 +00:00
return await response.json()
}
/**
* Make a POST request with OAuth2 Bearer token authentication
*
* @param path - The API endpoint path
* @param body - Request body data
* @param accessToken - OAuth2 access token
* @returns Response data from the API
*/
private async createWithBearer(path: string, body: any, accessToken: string): Promise<any> {
const url = `${this.clientConfig.baseUri}${path}`
console.log('OBPClientService: POST request with Bearer token to:', url)
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
})
if (!response.ok) {
const errorText = await response.text()
console.error('OBPClientService: POST request failed:', response.status, errorText)
throw new OBPAPIError(response.status, errorText)
2025-12-01 10:28:40 +00:00
}
2025-03-07 16:21:10 +00:00
2025-12-01 10:28:40 +00:00
return await response.json()
2025-03-07 16:21:10 +00:00
}
2025-12-01 10:28:40 +00:00
/**
* Make a PUT request with OAuth2 Bearer token authentication
*
* @param path - The API endpoint path
* @param body - Request body data
* @param accessToken - OAuth2 access token
* @returns Response data from the API
*/
private async updateWithBearer(path: string, body: any, accessToken: string): Promise<any> {
const url = `${this.clientConfig.baseUri}${path}`
console.log('OBPClientService: PUT request with Bearer token to:', url)
2025-12-01 10:28:40 +00:00
const response = await fetch(url, {
method: 'PUT',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
})
2025-12-01 10:28:40 +00:00
if (!response.ok) {
const errorText = await response.text()
console.error('OBPClientService: PUT request failed:', response.status, errorText)
throw new OBPAPIError(response.status, errorText)
2025-12-01 10:28:40 +00:00
}
return await response.json()
}
/**
* Make a DELETE request with OAuth2 Bearer token authentication
*
* @param path - The API endpoint path
* @param accessToken - OAuth2 access token
* @returns Response data from the API
*/
private async discardWithBearer(path: string, accessToken: string): Promise<any> {
const url = `${this.clientConfig.baseUri}${path}`
console.log('OBPClientService: DELETE request with Bearer token to:', url)
const response = await fetch(url, {
method: 'DELETE',
headers: {
2025-12-01 10:28:40 +00:00
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
})
2025-12-01 10:28:40 +00:00
if (!response.ok) {
const errorText = await response.text()
console.error('OBPClientService: DELETE request failed:', response.status, errorText)
throw new OBPAPIError(response.status, errorText)
2025-12-01 10:28:40 +00:00
}
2025-12-01 10:28:40 +00:00
return await response.json()
}
2023-05-03 17:17:01 +00:00
}