nestjs-sap-rfc
v4.0.5
Published
NestJS SAP RFC Client, providing convenient ABAP business logic consumption from NestJS
Downloads
1,077
Readme
📚 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:
- [x] Dynamic Configuration
- [x] Transaction with auto commit and rollback
- [x] Resource injection by name
- [x] Update to node-rfc 3.x