Skip to content

Instantly share code, notes, and snippets.

@NicolaasZA
Last active September 23, 2019 12:31
Show Gist options
  • Save NicolaasZA/c9daadd3a68611b4cd164493002049b4 to your computer and use it in GitHub Desktop.
Save NicolaasZA/c9daadd3a68611b4cd164493002049b4 to your computer and use it in GitHub Desktop.
Retry SOAP calls until a satisfactory result is returned, or maximum retries are met. NOTE: Still uses deprecated HTTP functionality.
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Http, Headers } from '@angular/http';
export interface ISoapAction {
name: string;
namespace: string;
}
@Injectable({
providedIn: 'root'
})
export class SoapService {
constructor( public http: Http ) { }
public post(serviceUrl: string, authKey: string, action: ISoapAction, params): Observable<any> {
const sr =
`<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">`
+ (authKey.length === 0 ? `` : this.generateAuthHeader(action.namespace, authKey))
+ `<soap:Body><` + action.name + ` xmlns="` + action.namespace + `">`
+ params
+ `</` + action.name + `></soap:Body></soap:Envelope>`;
const head = new Headers({ 'Content-Type': 'text/xml' });
return this.http.post(serviceUrl + '?op=' + action.name, sr, { headers: head })
.pipe(map((res: any) => {
// console.log(res);
const dom = new DOMParser().parseFromString(res._body, 'text/xml');
let result = dom.childNodes[0].childNodes[0].childNodes[0].childNodes[0].childNodes[0].nodeValue;
if (this.isJson(result)) {
result = JSON.parse(result);
}
// console.log(result);
return result;
}));
}
private generateAuthHeader(namespace: string, authKey: string) {
if (authKey && authKey.length > 0) {
return `<soap:Header><AuthHeader xmlns="` + namespace + `"><AuthKey>` + authKey + `</AuthKey></AuthHeader></soap:Header>`;
}
return '';
}
public isJson(str: string) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
}
import { SoapService, ISoapAction } from 'soap.service';
@Injectable({
providedIn: 'root'
})
export class WSService {
constructor(private soap: SoapService) { }
private retryMax = 5;
private retryDelay = 1000; // Delay between retrying
private someAction: ISoapAction = {
namespace: 'https://some.domain.com/ws_ServiceName/',
name: 'SOAPAction'
};
public callSoap(serviceURL: string, serviceKey: string, params) {
return new Promise<{ Response: any, ErrorMessage: string }>((resolve, reject) => {
let triesCounter = 1;
const intervalTimer = setInterval(() => {
this.soap
.post(serviceURL, serviceKey, this.someAction, params)
.subscribe(result => {
// Success conditions here in this if statement.
if (result.Success) {
// When satisfied, call clearInterval to stop the retries, and -
clearInterval(intervalTimer);
// Call resolve to resolve the promise and let the calling function handle the result.
resolve({
Response: result,
ErrorMessage: ''
});
} else {
if (triesCounter >= this.retryMax) {
// Maximum retries are met, so we need to stop retrying, and -
clearInterval(intervalTimer);
// Call reject to pass along the failure to the calling function.
reject({ Response: undefined, ErrorMessage: 'No response after ' + triesCounter + ' tries.' });
} else {
// Implement the counter and try again.
triesCounter += 1;
}
}
}, err => {
// Personal choice here on whether to stop trying when an error occurs.
// Be sure to increment the retry counter and max checker here if you want to continue.
clearInterval(intervalTimer);
reject({ Response: undefined, ErrorMessage: err.message });
});
}, this.retryDelay);
});
}
}
@NicolaasZA
Copy link
Author

This can work with any http call as well. Essentially, you nest the call inside a setInterval that you stop when you are happy the the response. This is all done inside a promise to send the result back to the caller.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment