How to consume SOAP services in NestJS?

Viewed 2439

I have to consume a SOAP service in NestJs for one of my projects. I am trying to consume a dummy SOAP service from web. Below are the details -

URL -

http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL

Method - POST

Headers -

Content-Type: text/xml

Request Body -

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
    <Body>
        <CapitalCity xmlns="http://www.oorsprong.org/websamples.countryinfo">
            <sCountryISOCode>IN</sCountryISOCode>
        </CapitalCity>
    </Body>
</Envelope>

Response Body -

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <m:CapitalCityResponse xmlns:m="http://www.oorsprong.org/websamples.countryinfo">
            <m:CapitalCityResult>New Delhi</m:CapitalCityResult>
        </m:CapitalCityResponse>
    </soap:Body>
</soap:Envelope>

Now I am not able to figure out how to consume this service in my NestJs dummy application. By exploring for quite sometime, I found a library nestjs-soap, which I installed and configured as mentioned below -

npm install nestjs-soap --save

My app.module.ts -

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SoapModule } from 'nestjs-soap';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true
    }),
    SoapModule.registerAsync([
      { name: 'MY_DUMMY_CLIENT', uri: `http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL` }
    ])
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

My app.service.ts -

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

@Injectable()
export class AppService {

  constructor(@Inject('MY_DUMMY_CLIENT') private readonly myDummyClient: Client) {}

  getHello(): string {
    return process.env.APP_MESSAGE;
  }

  getDetails(): string {
    return process.env.APP_DETAILS;
  }

  asyncGetCountryCapital() {
    //this.myDummyClient.
  }
}

As the documentation I referred is not in detail, I am not able to figure out how to call the SOAP service within asyncGetCountryCapital() function.

2 Answers

Today I needed to do the same thing and turns out that the documentation of nestjs-soap is not so clear.

After trying a few things, this is what worked for me.

1. Using method

The docs for this is here.

Example without sending parameters

Module:

SoapModule.register({
    clientName: 'CountryInfoService',
    uri: 'http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?wsdl',
})

Controller:

import { Client } from 'nestjs-soap';

constructor(
    @Inject('CountryInfoService') private readonly soapClient: Client,
) {}

@Get('soap')
soap() {
    return new Promise((resolve, reject) => {
        this.soapClient.ListOfContinentsByName(null, (err, res) => {
            if (res) {
                resolve(res);
            } else {
                reject(err);
            }
        });
    });
}

Notice the first parameter, I needed to pass null (can be {} too) because without it, I cannot declare the function in the second parameter.

Also, I have encapsulated it using new Promise() to be able to return it to the client.

Example sending parameters

Module:

Let's use another uri for this, this is the only one that I could found out there.

SoapModule.register({
    clientName: 'NumberConversion',
    uri: 'https://www.dataaccess.com/webservicesserver/NumberConversion.wso?wsdl',
})

Controller:

import { Client } from 'nestjs-soap';

constructor(
    @Inject('NumberConversion') private readonly soapClient: Client,
) {}

@Get('soap')
soap() {
    return new Promise((resolve, reject) => {
        this.soapClient.NumberToWords({ ubiNum: 235 }, (err, res) => {
            if (res) {
                resolve(res);
            } else {
                reject(err);
            }
        });
    });
}

Notice the first parameter, you need to pass an object with any properties you need.

2. Using methodAsync

The docs for this is here.

Example without sending parameters

@Get('soap')
async soap() {
    return await this.soapClient.YourFunctionNameAsync(null);
}

Example sending parameters

@Get('soap')
async soap() {
    return await this.soapClient.YourFunctionNameAsync({a: 1, b: 'hi'});
}

The key here is to add the word Async at the end of your function name. Example, taking the function ListOfContinentsByName from before, the name will be ListOfContinentsByNameAsync.

--

I got this solution looking at the nodejs soap library closely. The first example about how to use it, shows that you need to have a client function and a method function.

Then, looking at the code on GitHub of the nestjs-soap library, I saw that they are giving you only the client function, not both.

You/we need to provide the method function, example:

Using method

// The second parameter as a function is the key
this.soapClient.YourFunctionName(null, (err, res) => {
});

Using methodAsync

// Add the word `Async` at the end of your function name
const result = await this.soapClient.YourFunctionNameAsync({a: 1, b: 'hi'});

Hope it's helpful.

I found how to use it and is in the documentation. You need to call

this.soapClient.describe(), and in the response you have all the methods that the client allows.

:)

Related