Git Product home page Git Product logo

nestjs-soap's Introduction

NPM Version Package License NPM Downloads

Nestjs Soap

Nestjs module wrapper for soap npm package

Compatibility

For nestjs < v8.4.0 use v2 package.

For nestjs >= v8.4.0 use v3 package.

Install

npm install nestjs-soap

Or, if you use yarn

yarn add nestjs-soap

Documentation

Getting Started

After installing the package, just import the SoapModule on the module you want to use the soap client.

import { Module } from '@nestjs/common';
import { SoapModule } from 'nestjs-soap';

@Module({
  imports: [
    SoapModule.register(
      { clientName: 'MY_SOAP_CLIENT', uri: 'http://yourserver/yourservice.wso?wsdl' },
    ),
  ],
})
export class ExampleModule {}

The register or forRoot function receives a SoapModuleOptions object. You can register as many clients as you need, each with an unique clientName.

Another way to import the SoapModule is using forRootAsync or registerAsync, like other factory provider. It receives a SoapModuleAsyncOptions object. Our factory function can be async and can inject dependencies through inject:

import { Module } from '@nestjs/common';
import { SoapModule, SoapModuleOptions } from 'nestjs-soap';
import { ConfigService, ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    SoapModule.forRootAsync(
      { 
        clientName: 'MY_SOAP_CLIENT',
        imports: [ConfigModule],
        inject: [ConfigService],
        useFactory: async (
          configService: ConfigService,
        ): Promise<SoapModuleOptions> => ({
          uri: configService.get<string>('soap.uri'),
          auth: {
            type: 'basic',
            username: configService.get<string>('soap.username'),
            password: configService.get<string>('soap.password'),
          },
        }),        
      }
    ),
  ],
})
export class ExampleModule {}

Then, inject the client where you want to use it.

import { Inject, Injectable } from '@nestjs/common';
import { Client } from 'nestjs-soap';

@Injectable()
export class ExampleService {
  constructor(@Inject('MY_SOAP_CLIENT') private readonly mySoapClient: Client) {}

  async exampleFunction() {
    return await this.mySoapClient.YourFunctionAsync();
  }
}

The injected Client is from the soap npm package. This example is using the soap method async from soap package. From here, please follow the Client use instructions on the soap repository.

Soap Module Factory

You can also create your own factory implemeting SoapModuleOptionsFactory

import { Injectable, Inject } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SoapModuleOptionsFactory, SoapModuleOptionsFactoryType } from 'nestjs-soap';

@Injectable()
export class ExampleSoapConfigService implements SoapModuleOptionsFactory {
  constructor(
    @Inject(ConfigService) private readonly configService: ConfigService
  )

  createSoapModuleOptions(): SoapModuleOptionsFactoryType {
    return {
      uri: configService.get<string>('soap.uri'),
      auth: {
        type: 'basic',
        username: configService.get<string>('soap.username'),
        password: configService.get<string>('soap.password'),
      },
    };
  }
}

Then, import it using useClass or useExisting:

import { Module } from '@nestjs/common';
import { SoapModule, SoapModuleOptions } from 'nestjs-soap';
import { ExampleSoapConfigService } from './example-config'

@Module({
  imports: [
    SoapModule.forRootAsync(
      { 
        clientName: 'MY_SOAP_CLIENT',
        useClass: ExampleSoapConfigService        
      }
    ),
  ],
})
export class ExampleModule {}

Note: for the useExisting provider you need to import the module containing the ExampleSoapConfigService provider.

SoapModuleOptions

clientName: The unique client name for class injection.

uri: The SOAP service uri.

auth (optional): Basic or WSSecurity authentication. Fields type (basic or wssecurity), username and password are required. For the WSSecurity options field, refer to soap-repository

clientOptions (optional): The soap client options as in soap repository.

SoapModuleAsyncOptions

clientName: The unique client name for class injection.

inject: Array of dependencies to be injected.

useClass: A class implementing SoapModuleOptionsFactory.

useExisting: An injectable class implementing SoapModuleOptionsFactory.

useFactory: A factory function returning a SoapModuleOptions object.

imports: Array of modules containing the injected dependencies.

scope: Injection scope of the injected provider.

nestjs-soap's People

Contributors

ammarnajjar avatar gmqz avatar kleberoliveira avatar kleberoliveira-sharecare avatar lehh avatar zier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

nestjs-soap's Issues

How can i pass options to message.

Hello, i need to refactor this code:

var SoapClient = require('soap');
var options = {
    'trace': 1,
    "overrideRootElement": {
        "namespace": "myns",
        "xmlnsAttributes": [{
            "name": "xmlns:ns2",
            "value": "http://russianpost.org/operationhistory"
        }]
    },
    forceSoap12Headers: true,
    connection: 'keep-alive',
    'soap_version': 2
};
SoapClient.createClient('./local_wsdl.xml', options, function (err, client) {
    client.getOperationHistory(
        {
        'ns1:OperationHistoryRequest': {
            'ns1:Barcode': trackValue,
            'ns1:MessageType': 0,
            'ns1:Language': 'RUS',
        },
        'ns1:AuthorizationHeader': {
            'ns1:login': login,
            'ns1:password': password,
        },
    },
    (err, result) => {
        if (err) {
            console.log(err);

            return;
        }

        console.log(result.OperationHistoryData);
    }
    );
}

so i need to pass options, while send a message, and i try this:

async getOperationHistory() {
        let options = {            
            'trace': 1,
            "overrideRootElement": {
                "namespace": "ns2",
                "xmlnsAttributes": [{
                    "name": "xmlns:ns2",
                    "value": "http://russianpost.org/operationhistory"
                }]
            },
            forceSoap12Headers: true,
            connection: 'keep-alive',
            'soap_version': 2
        }
        this.postClient.addHttpHeader('Content-Type', 'xml');
        return await this.postClient.getOperationHistory
        (
            {
                'ns2:OperationHistoryRequest': {
                    'ns2:Barcode': '',
                    'ns2:MessageType': 0,
                    'ns2:Language': 'RUS',
                },
                'ns2:AuthorizationHeader': {
                    'ns2:login': ,
                    'ns2:password': ,
                }

            },
            (r, e) => {
                if (e) console.log(e.config.data, e.data);
            },
            options,
        )
    }

but this doesn't work.

soap server?

does this wrapper provide any integration for the soap server listen capability of the soap lib?

Nest.js 10,安装依赖失败

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: [email protected]
npm ERR! Found: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/common
npm ERR!   @nestjs/common@"^10.0.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @nestjs/common@"^8.4.0 || ^9.0.0" from [email protected]
npm ERR! node_modules/nestjs-soap
npm ERR!   nestjs-soap@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

Allow @nestjs/common@^9

Minor changes on @nest ^9 may easily allow usage with this version

npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/common
npm ERR!   @nestjs/common@"^9.0.4" from the root project
npm ERR!   peer @nestjs/common@"^7.0.0 || ^8.0.0 || ^9.0.0" from @nestjs/[email protected]
npm ERR!   node_modules/@nestjs/axios
npm ERR!     @nestjs/axios@"^0.1.0" from the root project
npm ERR!   7 more (@nestjs/config, @nestjs/core, @nestjs/mongoose, ...)
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @nestjs/common@"^6.10.0 || ^7.0.0 || ^8.0.0" from [email protected]
npm ERR! node_modules/nestjs-soap
npm ERR!   nestjs-soap@"^2.2.2" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: @nestjs/[email protected]
npm ERR! node_modules/@nestjs/common
npm ERR!   peer @nestjs/common@"^6.10.0 || ^7.0.0 || ^8.0.0" from [email protected]
npm ERR!   node_modules/nestjs-soap
npm ERR!     nestjs-soap@"^2.2.2" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

Please add Request scope for the Injectable items

Hi Team,

Thanks for the great work again. Could you please give provision for Request scope as that can be really necessary in various use cases. For example if we would need to change the soap url per request based on locale. This is an urgent need and would love to know if it can be done really soon and may be the ETA if you find this a valid request, @lehh .

New version for soap 1.0.0

Hi,

Is there a version using soap lib 1.0.0? Now, netsjs-soap package depends on soap 0.45.0.

Thanks,
KF

NestJS app cannot start when a remote SOAP service is unavailable

Hello,
and thank you for your work, its appreciated!

I am using nestjs-soap (version 1) to call an external, 3rd party SOAP service. The problem is, this 3rd party SOAP service is not always available, its often down for maintenance. In such moment, my NestJS application will not start. It throws an error like:

[Nest] 3548   - 02/05/2022, 6:52:27 PM   [ExceptionHandler] write EPROTO 16936:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:c:\ws\deps\openssl\openssl\ssl\record\ssl3_record.c:332:
 +716ms
Error: write EPROTO 16936:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:c:\ws\deps\openssl\openssl\ssl\record\ssl3_record.c:332:

    at D:\projects\ven\vet-api\node_modules\nestjs-soap\dist\soap-utils.js:19:19
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

I've tracked this down to:

throw new common_1.ServiceUnavailableException(err);

This is the way I register the SoapModule

SoapModule.registerAsync([{ 
    name: 'VAT_SOAP_CLIENT', 
    uri: 'https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl' 
}]),

As far as I understood, the moment we import the module, it tries to connect to that service immediately. Well, if my NestJS app is already started and the SOAP service is unavailable at some moment, that is fine, I can handle this case.

The problem is when the SOAP service is unavailable when the NestJS app is build and I try to start it. It wouldn't start. No matter the way we initialize the SoapModule, we just pass a config object and it tries to connect immediately.

Is there a way to postpone the connection to the SOAP service to the moment where we actually want to make a call, not at the moment when the module is registered?

Getting error while injecting ConfigService in SoapModule

I've created the following module:


import { Module } from '@nestjs/common';
import { OmnifinController } from './omnifin.controller';
import { OmnifinService } from './omnifin.service';
import { SoapModule, SoapModuleOptions } from 'nestjs-soap';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule,
    SoapModule.forRootAsync([
      {
        name: "OMNIFIN_CLIENT",
        imports: [ConfigModule],
        inject: [ConfigService],
        useFactory: async (configService: ConfigService): Promise => (
          {
            uri: configService.get('omnifin.url'),
          }
        )
      }
    ])
  ],
  controllers: [OmnifinController],
  providers: [OmnifinService]
})
export class OmnifinModule {}

which is working properly with SoapModule.registerAsync, but giving the following error with forRootAsync:


Nest can't resolve dependencies of the SoapConfigOptionsOMNIFIN_CLIENT (?). Please make sure that the argument ConfigService at index [0] is available in the SoapModule context.

Potential solutions:
- If ConfigService is a provider, is it part of the current SoapModule?
- If ConfigService is exported from a separate @Module, is that module imported within SoapModule?
  @Module({
    imports: [ /* the Module containing ConfigService */ ]
  })

Environment


NestJS version: 8.1.1
NestJS Dynamoose version: 0.3.3
Dynamoose version: 2.8.2

 
For Tooling issues:
- Node version: 14.15.3
- Platform:  Mac, Linux

Cannot import SoapModule correctly

Hi there.

Here is my module.

@Module({ imports: [ SoapModule.registerAsync({ clientName: 'MY_SOAP_CLIENT', imports: [ConfigModule], inject: [ConfigService], useFactory: async ( configService: ConfigService, ): Promise<SoapModuleOptions> => ({ uri: configService.get<string>('SOAP_URL'), clientName: 'MY_SOAP_CLIENT', auth: { type: 'basic', username: configService.get<string>('SOAP_USERNAME'), password: configService.get<string>('SOAP_PASSWORD'), }, }), }), ], controllers: [LmsManagementController], providers: [LmsManagementService], })

And my service constructor and function.

@Inject('MY_SOAP_CLIENT') private readonly mySoapClient: Client
console.log(await this.mySoapClient.GetKey());

Client always says null, not able to console any other function in it.

What is the problem exactly?

NestJS Soap Client with Self-Signed certificates

Hey all,
I'd like to send XML request with nestjs-soap library, but it throws an error with installed self-signed certificates, like:

ERROR [SoapModule] self-signed certificate in certificate chain

Can anyone help me through this?
Thanks!

Not able to insert a local WSDL file in SoapModule.register({ uri:

Hello!

I facing a problem when i try to insert a relative local path as uri.

the code is something like
SoapModule.register({ clientName: 'SOAP_GESTIONE_PRIVACY', uri: 'http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?wsdl', clientOptions: { disableCache: true, }, }),

and i want to change the uri with a local file located in a relative path such ./src/CountryInfoService.wsdl.. is it possible?

anyway Cool Lib! Man

Thanks

"path" argument

Getting error - [Nest] 4256 - ERROR [SoapModule] The "path" argument must be of type string or an instance of Buffer or URL. Received undefined

  • An error occurred while creating the soap client. Check the SOAP service URL and status.

My code:

import { Module } from "@nestjs/common";
import { SoapModule, SoapModuleOptions } from "nestjs-soap";
import { ConfigService, ConfigModule } from "@nestjs/config";

@Module({
  imports: [
    SoapModule.forRootAsync({
      clientName: "MY_SOAP_CLIENT",
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (
        configService: ConfigService
      ): Promise<SoapModuleOptions> => ({
        clientName: "MY_SOAP_CLIENT",
        uri: configService.get<string>(
          "MY_API_URL_IS_HERE"
        ),
        auth: {
          username: configService.get<string>("MY_USERNAME_HERE"),
          password: configService.get<string>("MY_PASSWORD_HERE"),
        },
      }),
    }),
  ],
})
export class SoapM {}

Module '"@nestjs/common"' has no exported member 'ModuleMetadata'

Hi,

I have an error when running my NestJS app that states that Module '"@nestjs/common"' has no exported member 'ModuleMetadata'.
I am running NestJS 7.0.0 (on Node 12) and nestjs-soap 2.2.1 (although I tried with nestjs-soap 2.0.0 and get the same error).

The console output is the following :

node_modules/nestjs-soap/dist/soap-module-options.type.d.ts:2:10 - error TS2305: Module '"@nestjs/common"' has no exported member 'ModuleMetadata'.

2 import { ModuleMetadata, Type } from '@nestjs/common';

When I remove the ModuleMetadata import from the soap-module-options.type.d.ts, my IDE suggests me to import ModuleMetadata from '@nestjs/common/interfaces' which seems to fix the problem.

Note that it is not possible for me to upgrade to a newer version of NestJS.

Do you know what could be the problem please?

Many thanks in advance!

Add WSSecurity auth method

Hi team,

What we need:
We are using this great package, but the 3rd party SOAP server changed the authentication method from Basic to WSSecurity. So I'm wondering if you are planning to add this authentication method...

Proposal:
Keeping the SoapModuleOptions structure and add some optional properties to support other authentication methods that node-soap actually supports.

Add types to src/soap-module-options.type.ts

....
export type BasicAuth = {
  type?: string
  username: string;
  password: string;
};

export type WSSecurityType = {
  type: string
  username: string;
  password: string;
  options?: string;
};

export type WSSecurityOptions = {
  passwordType?: string;
  hasTimeStamp?: boolean;
  hasTokenCreated?: boolean;
  hasNonce?: boolean;
  mustUnderstand?: boolean,
  actor?: string;
};

export type SoapModuleOptions = {
  uri: string;
  clientName: string;
  auth?: BasicAuth | WSSecurityType;
  clientOptions?: IOptions;
};
....

Change how to set the security method in src/soap.service.ts

...
try {
  const client = await createClientAsync(options.uri, options.clientOptions);
  
  if (!options.auth) return client;
  
  const {username, password} = options.auth;
  
  const authMethod: ISecurity = options.auth.type === 'WSSecurity'
    ? new WSSecurity(username, password, (options.auth as WSSecurityType).options)
    : new BasicAuthSecurity(username, password);
  
  client.setSecurity(authMethod);
  
  return client;
} catch (err) {
...

Example

import { Module } from '@nestjs/common';
import { SoapModule, SoapModuleOptions } from 'nestjs-soap';
import { ConfigService, ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    SoapModule.forRootAsync(
      { 
        clientName: 'MY_SOAP_CLIENT',
        imports: [ConfigModule],
        inject: [ConfigService],
        useFactory: async (
          configService: ConfigService,
        ): Promise<SoapModuleOptions> => ({
          uri: configService.get<string>('soap.uri'),
          auth: {
            type: 'WSSecurity',
            username: configService.get<string>('soap.username'),
            password: configService.get<string>('soap.password'),
            options: {.....}
          },
        }),        
      }
    ),
  ],
})
export class ExampleModule {}

What do you think?
I can create a PR if you want with this proposal....

Finally, thanks for the great work on this package.

Always getting the same error (v3)

In the browser or SoapUI have no problem to load the wsdl, but using this library always show the same error. (nestjs >= v8.4.0)

--
[Nest] 30912 - 10/28/2022, 5:27:01 PM ERROR [SoapModule] Cannot read properties of undefined (reading 'create')

  • An error occurred while creating the soap client. Check the SOAP service URL and status.

Screen Shot 2022-10-28 at 17 25 04

forRootAsync takes an array but instantiates only the last client in the array

@lehh

For the below code snippet:
The client-2 is only instantiated

const getOptions = (jsonConfig: any, serviceId: string, subModule?: string): SoapModuleOptions => {
  //config returns a json of format 
  //"SAMPLE": {
  //    "SUB1": {
  //      "uri": "https://sub1.asmx?wsdl"
  //    },
  //    "SUB2": {
  //      "uri": "https://sub2.asmx?wsdl"
  //   }
  // }
  return {
    uri: jsonConfig[serviceId][subModule].uri,
  };
};

export const Soap = SoapModule.forRootAsync([
  { 
    name: 'CLIENT-1',
    inject: [JSON_CONFIG],
    useFactory: (jsonConfig: any) => getOptions(jsonConfig, 'SAMPLE', 'SUB1'),
  },
  {
    name: 'CLIENT-2,
    inject: [JSON_CONFIG],
    useFactory: (jsonConfig: any) => getOptions(jsonConfig, 'SAMPLE', 'SUB2'),
  },
]);

Also, FYI:
in the main module the Soap is imported as such:

import { Soap } from '.../soap.config';
@Module({
  imports: [Soap],
  controllers: [],
  providers: []
    })

Does nestjs-soap supports NTLM authentication?

I'm trying to consume a SOAP-based web service using this package (great work btw!). The API requires NTLM based authentication, which the base soap package supports, but I'm not sure how to implement that kind of auth standard using your module wrapper.

SoapModule.forRootAsync(
  { 
   ...
    useFactory: async (
      configService: ConfigService,
    ): Promise<SoapModuleOptions> => ({
      uri: configService.get<string>('soap.uri'),
      auth: {
        type: 'basic',                 // <-- 'ntlm' ?
        username: configService.get<string>('soap.username'),
        password: configService.get<string>('soap.password'),
      },
    }),        
  }
),

Please advise

Create multiple clients in a single module

Hi everyone,

Is there a feature to create multiple SOAP clients with separate configs in a single module? As I've seen in the examples in documentation, there were only cases with a single client. I could have a workaround with separate modules for each service, but it seems redundant to me.

I am talking about something like this:

SoapModule.registerAsync([ { clientName: 'WSDL1_SOAP_CLIENT', inject: [ConfigService], useFactory(configService: ConfigService) { return { uri: configService.get('WSDL1_URL'), }; }, }, { clientName: 'WSDL2_SOAP_CLIENT', inject: [ConfigService], useFactory(configService: ConfigService) { return { uri: configService.get('WSDL2_URL'), }; }, } ])

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.