NestJS SAP RFC Client
Description
NestJS SAP RFC Client, providing convenient ABAP business logic consumption from NestJS
Installation
npm install nestjs-sap-rfc --save
Getting Started
Register SapModule module in app.module.ts
import { SapModule } from 'nestjs-sap-rfc';
import { Module } from '@nestjs/common';
@Module({
imports: [
SapModule.createPool({
isGlobal: true, // for global module
name: 'service_name', // for multiple modules (OPTIONAL)
connectionParameters: {
/* see RfcConnectionParameters */
},
clientOptions: {
/* see RfcClientOptions */
},
poolOptions: {
/* see RfcPoolOptions */
},
}),
],
})
export class AppModule {}
Connection Pool (Async Module)
import { SapModule } from 'nestjs-sap-rfc';
import { Module } from '@nestjs/common';
@Module({
imports: [
SapModule.createPoolAsync({
isGlobal: true, // for global module
name: 'service_name', // for multiple modules (OPTIONAL)
useFactory: () => {
return {
connectionParameters: {
/* see RfcConnectionParameters */
},
clientOptions: {
/* see RfcClientOptions */
},
poolOptions: {
/* see RfcPoolOptions */
},
};
},
}),
],
})
export class AppModule {}
Connection Pool (Async Module + ConfigService)
import { SapModule } from 'nestjs-sap-rfc';
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Module({
imports: [
SapModule.createPoolAsync({
isGlobal: true, // for global module
name: 'service_name', // for multiple modules (OPTIONAL)
useFactory: (config: ConfigService) => {
return {
connectionParameters: {
/* see RfcConnectionParameters */
/* config.get(...) */
},
clientOptions: {
/* see RfcClientOptions */
/* config.get(...) */
},
poolOptions: {
/* see RfcPoolOptions */
/* config.get(...) */
},
};
},
inject: [ConfigService],
}),
],
})
export class AppModule {}
import { SapModule } from 'nestjs-sap-rfc';
import { Module } from '@nestjs/common';
@Module({
imports: [
SapModule.createClient({
isGlobal: true, // for global module
name: 'service_name', // for multiple modules (OPTIONAL)
connectionParameters: {
/* see RfcConnectionParameters */
},
clientOptions: {
/* see RfcClientOptions */
},
}),
],
})
export class AppModule {}
Direct Client (Async Module)
import { SapModule } from 'nestjs-sap-rfc';
import { Module } from '@nestjs/common';
@Module({
imports: [
SapModule.createClientAsync({
isGlobal: true, // for global module
name: 'service_name', // for multiple modules (OPTIONAL)
useFactory: () => {
return {
connectionParameters: {
/* see RfcConnectionParameters */
},
clientOptions: {
/* see RfcClientOptions */
},
};
},
}),
],
})
export class AppModule {}
Direct Client (Async Module + ConfigService)
import { SapModule } from 'nestjs-sap-rfc';
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Module({
imports: [
SapModule.createClientAsync({
isGlobal: true, // for global module
name: 'service_name', // for multiple modules (OPTIONAL)
useFactory: (config: ConfigService) => {
return {
connectionParameters: {
/* see RfcConnectionParameters */
},
clientOptions: {
/* see RfcClientOptions */
},
};
},
inject: [ConfigService],
}),
],
})
export class AppModule {}
Inject SapService
import { InjectSapService, SapService, SapRfcObject, SapRfcStructure } from 'nestjs-sap-rfc';
import { Injectable } from '@nestjs/common';
// RfcStructure
type PositionData = SapRfcStructure; // SAP structure
// RfcStructure
interface NestedData extends SapRfcStructure {
readonly E_NESTED?: string; // SAP field name
}
// MySapInterface
interface MySapInterface extends SapRfcObject {
readonly E_NAME?: string; // SAP field name
readonly E_DATA?: PositionData; // SAP field name
readonly E_DATA2?: NestedData; // SAP field name
readonly E_ERROR?: string; // SAP field name
readonly I_OBJID?: string; // SAP field name
}
@Injectable()
export class MyService {
/**
* @param {SapService} sapService
*/
constructor(
@InjectSapService()
private readonly sapService: SapService,
) {}
public async test(): MySapInterface {
return this.sapService.execute<MySapInterface>('rfcName', {
...rfcParams,
});
}
}
Inject SapService by name
import { InjectSapService, SapService, SapRfcObject, SapRfcStructure } from 'nestjs-sap-rfc';
import { Injectable } from '@nestjs/common';
// RfcStructure
type PositionData = SapRfcStructure; // SAP structure
// RfcStructure
interface NestedData extends SapRfcStructure {
readonly E_NESTED?: string; // SAP field name
}
// MySapInterface
interface MySapInterface extends SapRfcObject {
readonly E_NAME?: string; // SAP field name
readonly E_DATA?: PositionData; // SAP field name
readonly E_DATA2?: NestedData; // SAP field name
readonly E_ERROR?: string; // SAP field name
readonly I_OBJID?: string; // SAP field name
}
@Injectable()
export class MyService {
/**
* @param {SapService} sapService
*/
constructor(
@InjectSapService('service_name')
private readonly sapService: SapService,
) {}
public async test(): MySapInterface {
return this.sapService.execute<MySapInterface>('rfcName', {
...rfcParams,
});
}
}
Creating and using transactions
Transactions are created using SapService. Example:
import { InjectSapService, SapService, SapRfcObject, SapRfcStructure } from 'nestjs-sap-rfc';
import { Injectable } from '@nestjs/common';
// RfcStructure
type PositionData = SapRfcStructure; // SAP structure
// RfcStructure
interface NestedData extends SapRfcStructure {
readonly E_NESTED?: string; // SAP field name
}
// MySapInterface
interface MySapInterface extends SapRfcObject {
readonly E_NAME?: string; // SAP field name
readonly E_DATA?: PositionData; // SAP field name
readonly E_DATA2?: NestedData; // SAP field name
readonly E_ERROR?: string; // SAP field name
readonly I_OBJID?: string; // SAP field name
}
@Injectable()
export class MyService {
/**
* @param {SapService} sapService
*/
constructor(
@InjectSapService()
private readonly sapService: SapService,
) {}
public async runTransaction(): MySapInterface {
await this.sapService.transaction(async (sapClient: SapClient) => {
// call rfcs using sapClient
});
}
}
Everything you want to run in a transaction must be executed in a callback:
@Injectable()
export class MyService {
/**
* @param {SapService} sapService
*/
constructor(
@InjectSapService()
private readonly sapService: SapService,
) {}
public async runTransaction(): MySapInterface {
await this.sapService.transaction(async (sapClient: SapClient) => {
await sapClient.call('rfcName_1', {
...rfcParams,
});
await sapClient.call('rfcName_2', {
...rfcParams,
});
});
}
}
The most important restriction when working in a transaction is to ALWAYS use the provided instance of SapClient. All operations MUST be executed using the provided SapClient.
Test
# unit tests
$ npm run test
# test coverage
$ npm run test:cov
Generate Docs
The docs can be generated on-demand. This will produce a documentation folder with the required front-end files.
# generate docs for code
$ npm run doc
# generate docs for code and serve on http://localhost:8080
$ npm run doc:serve
Commitizen
commitizen is a command line utility that makes it easier to create commit messages following the conventional commit format specification.
Use npm run commit instead of git commit to use commitizen.
Built With
Roadmap
The following improvements are currently in progress:
- Dynamic Configuration
- Transaction with auto commit and rollback
- Resource injection by name
- Update to node-rfc 3.x