@contiva/sap-integration-suite-client
Version:
SAP Cloud Platform Integration API Client
733 lines (538 loc) • 23.3 kB
Markdown
# SAP Integration Suite Client
[](https://badge.fury.io/js/sap-integration-suite-client)
[](https://opensource.org/licenses/MIT)
A TypeScript library for SAP Cloud Integration APIs (part of SAP Integration Suite), developed by [Contiva GmbH](https://contiva.com).
Available on npm: [sap-integration-suite-client](https://www.npmjs.com/package/sap-integration-suite-client)
## 📋 Table of Contents
- [Quick Start](#-quick-start)
- [Features](#-features)
- [Installation](#-installation)
- [Configuration](#️-configuration)
- [Basic Usage](#-basic-usage)
- [API Examples](#-api-examples)
- [Integration Content](#integration-content-example)
- [Message Processing Logs](#message-processing-logs-example)
- [Security Content](#security-content-example)
- [Message Store](#message-store-example)
- [Log Files](#log-files-example)
- [Advanced Features](#-advanced-features)
- [Advanced Clients](#integration-content-advanced-example)
- [Extension Framework](#extending-your-project)
- [Error Handling](#-error-handling)
- [API Documentation](#-api-documentation)
- [Testing](#-testing)
- [Unit and Integration Tests](#unit-and-integration-tests)
- [End-to-End Tests](#end-to-end-tests)
- [Troubleshooting](#-troubleshooting)
- [License](#-license)
## 🚀 Quick Start
```bash
# Install the package
npm install sap-integration-suite-client
# Create a .env file with your SAP credentials
echo "SAP_BASE_URL=https://your-tenant.integrationsuitetrial-api.eu10.hana.ondemand.com/api/v1
SAP_OAUTH_CLIENT_ID=your-client-id
SAP_OAUTH_CLIENT_SECRET=your-client-secret
SAP_OAUTH_TOKEN_URL=https://your-tenant.authentication.eu10.hana.ondemand.com/oauth/token" > .env
```
```typescript
// Basic usage example
import SapClient from 'sap-integration-suite-client';
import dotenv from 'dotenv';
dotenv.config();
// Create client (reads from .env)
const client = new SapClient();
// List integration packages
async function listPackages() {
const packages = await client.integrationContent.getIntegrationPackages();
console.log(`Found ${packages.length} integration packages`);
packages.forEach(pkg => console.log(`- ${pkg.Name}`));
}
listPackages().catch(console.error);
```
## 🔍 Features
This client simplifies communication with SAP Integration Suite APIs:
- **Complete API Coverage**:
- Integration Content - Manage packages, flows, and artifacts
- Message Processing Logs - Monitor message execution
- Message Store - Access persisted messages and payloads
- Security Content - Manage credentials and certificates
- Log Files - Access HTTP and trace logs
- **Developer-Friendly**:
- TypeScript support with full type definitions
- Promise-based API
- OAuth and CSRF token handling
- Error handling with detailed information
- **Advanced Capabilities**:
- Bulk operations (retrieving packages with artifacts)
- Error statistics and performance analysis
- Extensible framework for custom clients
## 📦 Installation
```bash
# Using npm
npm install sap-integration-suite-client
# Using yarn
yarn add sap-integration-suite-client
# Using pnpm
pnpm add sap-integration-suite-client
```
## ⚙️ Configuration
You can configure the client through environment variables or direct parameters.
### Environment Variables (Recommended)
Create a `.env` file:
```env
# Required
SAP_BASE_URL=https://your-tenant.integrationsuitetrial-api.eu10.hana.ondemand.com/api/v1
SAP_OAUTH_CLIENT_ID=your-client-id
SAP_OAUTH_CLIENT_SECRET=your-client-secret
SAP_OAUTH_TOKEN_URL=https://your-tenant.authentication.eu10.hana.ondemand.com/oauth/token
# Optional
SAP_MAX_RETRIES=3
SAP_RETRY_DELAY=1500
# Redis Caching (Optional)
REDIS_CONNECTION_STRING=your-redis-host:6380,password=xxx,ssl=True,abortConnect=False
REDIS_ENABLED=true
```
Then initialize without parameters:
```typescript
import SapClient from 'sap-integration-suite-client';
import dotenv from 'dotenv';
dotenv.config();
const client = new SapClient(); // Reads from process.env
```
### Direct Configuration
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient({
baseUrl: 'https://your-tenant.integrationsuitetrial-api.eu10.hana.ondemand.com/api/v1',
oauthClientId: 'your-client-id',
oauthClientSecret: 'your-client-secret',
oauthTokenUrl: 'https://your-tenant.authentication.eu10.hana.ondemand.com/oauth/token',
// Optional settings
maxRetries: 3, // Default: 0
retryDelay: 1500, // Default: 1000 (ms)
normalizeResponses: true, // Default: true
enableCustomClients: true, // Default: true - Enable advanced client extensions
// Redis caching options
redisConnectionString: 'host:6380,password=xxx,ssl=True',
redisEnabled: true, // Default: false
forceRefreshCache: false, // Default: false - Force background revalidation
noCache: false // Default: false - Disable caching completely
});
```
> **Note**: The `baseUrl` should point to the `/api/v1` endpoint of your tenant's API service URL.
## 🚀 Redis Caching (Performance Optimization)
This library supports optional Redis-based caching to significantly improve performance and reduce load on SAP systems.
### Features
- **Stale-While-Revalidate Pattern**: Returns cached data immediately while updating in the background
- **Hostname-Aware**: Multi-tenant support with separate cache per SAP system
- **Smart TTL Configuration**:
- Standard APIs: 1 hour revalidation, 30 days storage
- Runtime APIs (MessageProcessingLogs, LogFiles): 5 minutes revalidation, 30 days storage
- **Selective Caching**: Automatically excludes downloads and binary data
- **Graceful Degradation**: Works seamlessly without Redis
### Setup
1. **Install and configure Redis** (Azure Redis Cache, local Redis, etc.)
2. **Configure environment variables**:
```env
REDIS_CONNECTION_STRING=your-redis.redis.cache.windows.net:6380,password=yourpassword,ssl=True,abortConnect=False
REDIS_ENABLED=true
```
3. **Use the client normally** - caching happens automatically:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient({
// SAP configuration...
redisEnabled: true,
redisConnectionString: process.env.REDIS_CONNECTION_STRING,
});
// First call: fetches from SAP and caches (slower)
const packages1 = await client.integrationContent.getIntegrationPackages();
// Second call: returns from cache (much faster!)
const packages2 = await client.integrationContent.getIntegrationPackages();
```
### Advanced Options
#### Force Refresh Cache
Force revalidation while still returning cached data (useful after deployments):
```typescript
const client = new SapClient({
// ... other config
redisEnabled: true,
forceRefreshCache: true // Forces background revalidation on every request
});
```
#### Disable Caching
Completely bypass cache for specific client instances:
```typescript
const client = new SapClient({
// ... other config
noCache: true // No cache reads or writes
});
```
### What Gets Cached?
**Cached:**
- All GET requests to SAP APIs
- Integration packages, flows, and configurations
- Security content metadata
- Message processing logs (with shorter TTL)
**Not Cached:**
- POST, PUT, DELETE requests
- Binary downloads (`/value`, `/$value`, `/download` endpoints)
- Custom API extensions (only direct SAP APIs are cached)
- Requests with `noCache: true`
### Performance Benefits
Typical performance improvements with caching enabled:
- **Cache Hit**: 50-95% faster response times
- **Reduced SAP Load**: Fewer API calls to SAP systems
- **Better Reliability**: Stale data served even during SAP outages (within TTL)
### Monitoring Cache
Enable debug mode to see cache behavior:
```typescript
process.env.DEBUG = 'true';
// Console will show:
// [SapClient] Cache miss: /IntegrationPackages
// [SapClient] Cache hit (fresh): /IntegrationPackages
// [SapClient] Cache needs revalidation (stale): /MessageProcessingLogs
```
## 💡 Basic Usage
After creating a client instance, you can access various API areas through properties:
```typescript
// Access different API clients
client.integrationContent // Integration Content API
client.messageProcessingLogs // Message Processing Logs API
client.messageStore // Message Store API
client.securityContent // Security Content API
client.logFiles // Log Files API
// Access advanced clients
client.integrationContentAdvanced // Enhanced Integration Content operations
```
## 📚 API Examples
### Integration Content Example
Manage integration packages, flows, and other artifacts:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function managePackages() {
// List packages (with pagination)
const packages = await client.integrationContent.getIntegrationPackages({ top: 5 });
console.log(`Found ${packages.length} packages`);
if (packages.length > 0) {
const packageId = packages[0].Id;
// Get integration flows in a package
const flows = await client.integrationContent.getIntegrationFlows(packageId);
console.log(`Package ${packages[0].Name} has ${flows.length} integration flows`);
// Get a specific flow
if (flows.length > 0) {
const flow = await client.integrationContent.getIntegrationFlowById(flows[0].Id);
console.log(`Flow details: ${flow?.Name}, Version: ${flow?.Version}`);
}
}
}
managePackages().catch(console.error);
```
### Message Processing Logs Example
Monitor and analyze message execution:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function monitorMessages() {
// Get failed messages from the last 24 hours
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const { logs } = await client.messageProcessingLogs.getMessageProcessingLogs({
filter: `Status eq 'FAILED' and LogEnd gt datetime'${yesterday.toISOString()}'`,
top: 10,
orderby: ['LogEnd desc']
});
console.log(`Found ${logs.length} failed messages in the last 24 hours`);
for (const log of logs) {
console.log(`Message: ${log.MessageGuid}, Flow: ${log.IntegrationFlowName}`);
// Get error details for a failed message
const errorInfo = await client.messageProcessingLogs.getLogErrorInformation(log.MessageGuid);
if (errorInfo) {
console.log(`Error: ${errorInfo.ErrorMessage}`);
}
}
}
monitorMessages().catch(console.error);
```
### Security Content Example
Manage security artifacts like keystores and credentials:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function manageKeystore() {
// List keystore entries
const entries = await client.securityContent.getKeystoreEntries('system');
console.log(`Found ${entries.length} entries in the system keystore`);
entries.forEach(entry => {
console.log(`- ${entry.Alias} (${entry.Type}), Valid until: ${entry.Validity}`);
});
}
manageKeystore().catch(console.error);
```
### Message Store Example
Access persisted messages and their payloads:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function accessMessageStore(messageGuid: string) {
// Get store entries for a message
const entries = await client.messageStore.getMessageStoreEntriesForMessage(messageGuid);
console.log(`Found ${entries.length} message store entries`);
if (entries.length > 0) {
// Get entry details
console.log(`Entry ID: ${entries[0].Id}, Type: ${entries[0].MsgType}`);
// Get payload (if available)
try {
const payload = await client.messageStore.getMessageStoreEntryPayload(entries[0].Id);
console.log('Payload retrieved successfully');
} catch (error) {
console.error('Failed to retrieve payload');
}
}
}
// Replace with a valid message GUID
accessMessageStore('your-message-guid').catch(console.error);
```
### Log Files Example
Access HTTP and trace logs:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function accessLogs() {
// List HTTP log files
const logs = await client.logFiles.getLogFiles({
filter: "LogFileType eq 'http'"
});
console.log(`Found ${logs.length} HTTP log files`);
if (logs.length > 0) {
const recentLog = logs[0];
console.log(`Recent log: ${recentLog.Name}, Size: ${recentLog.Size} bytes`);
// Download log content
if (recentLog.Name && recentLog.Application) {
const content = await client.logFiles.downloadLogFile(
recentLog.Name,
recentLog.Application
);
// In Node.js, convert content to string
if (Buffer.isBuffer(content)) {
const textContent = content.toString('utf-8').substring(0, 500);
console.log(`Log content preview: ${textContent}...`);
}
}
}
}
accessLogs().catch(console.error);
```
## 🔧 Advanced Features
### Integration Content Advanced Example
The library provides advanced clients with enhanced capabilities and **optimized performance**:
#### 🚀 Performance Optimizations
The `getPackagesWithArtifacts` method includes significant optimizations:
- **50% fewer API calls**: MessageMappings & ValueMappings are fetched via global endpoints
- **Concurrency control**: Prevents rate limiting (HTTP 429) errors
- **Configurable parallelization**: Adjust concurrency based on your system size
#### Basic Usage
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function advancedOperations() {
// Get packages with all their artifacts in a single operation (sequentially)
const packagesWithArtifacts = await client.integrationContentAdvanced.getPackagesWithArtifacts({
top: 5,
includeEmpty: false // Skip packages without artifacts
});
console.log(`Retrieved ${packagesWithArtifacts.length} packages with their artifacts`);
// Example of data available
if (packagesWithArtifacts.length > 0) {
const pkg = packagesWithArtifacts[0];
console.log(`Package: ${pkg.package.Name} (${pkg.package.Id})`);
console.log(`- Integration Flows: ${pkg.artifacts.integrationFlows.length}`);
console.log(`- Value Mappings: ${pkg.artifacts.valueMappings.length}`);
console.log(`- Message Mappings: ${pkg.artifacts.messageMappings.length}`);
console.log(`- Script Collections: ${pkg.artifacts.scriptCollections.length}`);
}
}
advancedOperations().catch(console.error);
```
#### ⚡ Parallel Mode with Optimal Concurrency
```typescript
// Fetch packages with optimal parallelization
const packagesWithArtifacts = await client.integrationContentAdvanced.getPackagesWithArtifacts({
parallel: true,
concurrency: 7 // Optimal for most systems (up to 100 packages)
});
// Monitor rate limit errors
const rateLimitErrors = client.integrationContentAdvanced.getRateLimitErrorCount();
if (rateLimitErrors > 0) {
console.warn(`⚠️ ${rateLimitErrors} rate limit errors occurred - consider reducing concurrency`);
}
```
#### 📊 Best Practices for Concurrency
| System Size | Recommended Concurrency | Notes |
|------------|------------------------|-------|
| Small (< 50 packages) | `concurrency: 10` | Safe for most small systems |
| Medium (50-100 packages) | `concurrency: 7` | **Default - optimal for most** |
| Large (100+ packages) | `concurrency: 5` | Start low, monitor 429 errors |
| Very Large (200+ packages) | `concurrency: 3-5` | Increase carefully |
**Finding your optimal concurrency:**
```bash
# Use the included test script
./find-optimal-concurrency.sh
# Or manually test different values
node your-script.js --concurrency 7
```
### Extending Your Project
You can extend the library with custom functionality without modifying the `node_modules` directory:
```typescript
// src/custom/FlowAnalytics.ts
import {
BaseCustomClient,
MessageProcessingLogsClient
} from 'sap-integration-suite-client';
// Create your custom client class
export class FlowAnalytics extends BaseCustomClient<MessageProcessingLogsClient> {
async getFlowPerformance(flowName: string, days = 7) {
const fromDate = new Date();
fromDate.setDate(fromDate.getDate() - days);
const { logs } = await this.client.getMessageProcessingLogs({
filter: `IntegrationFlowName eq '${flowName}' and Status eq 'COMPLETED' and LogEnd gt datetime'${fromDate.toISOString()}'`,
top: 100
});
// Calculate performance metrics
const durations = logs.map(log => {
const start = new Date(log.LogStart).getTime();
const end = new Date(log.LogEnd).getTime();
return end - start;
});
return {
count: logs.length,
avgDuration: durations.reduce((sum, d) => sum + d, 0) / durations.length || 0,
minDuration: Math.min(...durations) || 0,
maxDuration: Math.max(...durations) || 0
};
}
}
// src/custom/FlowAnalyticsFactory.ts
import { CustomClientFactory, MessageProcessingLogsClient } from 'sap-integration-suite-client';
import { FlowAnalytics } from './FlowAnalytics';
export class FlowAnalyticsFactory implements CustomClientFactory<MessageProcessingLogsClient, FlowAnalytics> {
create(baseClient: MessageProcessingLogsClient): FlowAnalytics {
return new FlowAnalytics(baseClient);
}
}
// src/index.ts - Using your custom client
import SapClient from 'sap-integration-suite-client';
import { FlowAnalyticsFactory } from './custom/FlowAnalyticsFactory';
const client = new SapClient();
// Register your custom factory
client.customClientRegistry.registerFactory('flow-analytics', new FlowAnalyticsFactory());
// Use your custom client
async function analyzeFlowPerformance() {
const analytics = client.customClientRegistry.create('flow-analytics', client.messageProcessingLogs);
const performance = await analytics.getFlowPerformance('MyIntegrationFlow');
console.log('Flow performance:', performance);
}
analyzeFlowPerformance().catch(console.error);
```
## 🎣 Error Handling
The client provides enhanced error objects with additional details:
```typescript
import SapClient from 'sap-integration-suite-client';
const client = new SapClient();
async function handleErrors() {
try {
// Try to get a non-existent package
await client.integrationContent.getIntegrationPackageById('non-existent-id');
} catch (error: any) {
console.error('Error occurred:');
console.error(`- Status Code: ${error.statusCode || 'N/A'}`);
console.error(`- Status Text: ${error.statusText || 'N/A'}`);
console.error(`- Message: ${error.message}`);
// SAP specific error details (if available)
if (error.responseData) {
console.error('- SAP Error:', error.responseData);
}
}
}
handleErrors();
```
## 📖 API Documentation
Eine vollständige API-Dokumentation mit allen Klassen, Methoden, Interfaces und Typen ist verfügbar.
### Dokumentation lokal generieren
```bash
# Dokumentation generieren
npm run docs
# Dokumentation im Browser öffnen
npm run docs:serve
```
Die Dokumentation wird mit [TypeDoc](https://typedoc.org/) generiert und enthält:
- 📚 Vollständige Methodensignaturen und Beschreibungen
- 🔍 TypeScript-Typen für alle APIs
- 💡 Code-Beispiele und Usage-Patterns
- 🔗 Verlinkte Referenzen zwischen Typen
**Weitere Details**: Siehe [DOCS.md](./DOCS.md) für eine ausführliche Anleitung zur Dokumentation.
## 🧪 Testing
Das Projekt enthält verschiedene Test-Typen, die für unterschiedliche Zwecke verwendet werden.
### Unit and Integration Tests
Normale Tests (Unit- und Integration-Tests) befinden sich in `tests/units/` und `tests/integration/` und werden bei `npm run test` ausgeführt:
```bash
npm run test
```
Diese Tests:
- Sind schnell und unabhängig
- Können Mock-Daten verwenden
- Werden automatisch bei jedem Test-Lauf ausgeführt
- Haben keine Abhängigkeiten zu echten SAP-Systemen
### End-to-End Tests
End-to-End-Tests arbeiten mit echten SAP-Systemen und echten Daten. Sie sind explizit getrennt von den normalen Tests und werden nur auf explizite Anforderung ausgeführt.
#### Einrichtung
1. Kopieren Sie die Beispiel-Umgebungsvariablen:
```bash
cp .env.e2e.example .env.e2e
```
2. Bearbeiten Sie `.env.e2e` und tragen Sie Ihre echten SAP-Credentials ein:
```env
SAP_BASE_URL=https://your-tenant.integrationsuitetrial-api.eu10.hana.ondemand.com/api/v1
SAP_OAUTH_CLIENT_ID=your-client-id
SAP_OAUTH_CLIENT_SECRET=your-client-secret
SAP_OAUTH_TOKEN_URL=https://your-tenant.authentication.eu10.hana.ondemand.com/oauth/token
REDIS_CONNECTION_STRING=redis://localhost:6379
REDIS_ENABLED=true
```
#### Ausführung
```bash
# Alle E2E-Tests ausführen
npm run test:e2e
# Watch-Mode für Entwicklung
npm run test:e2e:watch
# Verbose-Mode für detailliertes Logging
npm run test:e2e:verbose
```
#### Unterschiede zu normalen Tests
| Feature | Normale Tests | E2E-Tests |
|---------|--------------|-----------|
| Ausführung | `npm run test` | `npm run test:e2e` |
| Daten | Mock-Daten möglich | Echte SAP-Daten |
| Geschwindigkeit | Schnell | Langsamer (echte API-Calls) |
| Abhängigkeiten | Keine externen Systeme | Benötigt SAP-System |
| Timeout | 30 Sekunden | 60 Sekunden |
**Wichtig**: E2E-Tests werden **nicht** bei `npm run test` ausgeführt und sind standardmäßig in CI/CD-Pipelines deaktiviert.
Weitere Informationen finden Sie in der [E2E-Test-Dokumentation](./tests/e2e/README.md).
## ❓ Troubleshooting
Common issues and solutions:
### Authentication Problems
- **OAuth Errors**: Verify your Client ID, Client Secret, and Token URL
- **Permission Errors**: Ensure your OAuth client has the necessary roles assigned (IntegrationDeveloper, etc.)
### API Errors
- **404 Not Found**: Check that your `baseUrl` is correct and includes `/api/v1`
- **403 Forbidden**: Your client might lack necessary permissions for the API
- **CSRF Token Errors**: Ensure your base URL is correct and allows token fetch operations
### Environment-Specific Issues
- **Neo vs. Cloud Foundry**: Some APIs are environment-specific (Neo-only or CF-only)
- **Tenant Configuration**: Verify your tenant has the APIs you need enabled
## 📄 License
MIT © [Contiva GmbH](https://contiva.com)
---
Developed by Contiva GmbH - [https://contiva.com](https://contiva.com)