6

I am trying to build a shipment tracking tool using the Estes Shipment Tracking Web Services which use SOAP. I talked with their web support, and they are able to create a working request using SOAPUI that receives a valid response using my credentials. It would appear that my problem is the inability to replicate the request/response in SOAPUI with node.js. Why am I not able to replicate the SOAPUI request/response in node.js?

The following is the working raw request from SOAPUI that Estes web support used:

POST https://api.estes-express.com:443/ws/estesrtshipmenttracking.base.ws.provider.soapws:EstesShipmentTracking/estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Port HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder_shipmentTracking"
Content-Length: 468
Host: api.estes-express.com:443
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Authorization: Basic XXXXX

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="https://api.estes-express.com/ws/tools/shipment/tracking/v1.1/">
   <soapenv:Header/>
   <soapenv:Body>
      <v1:shipmentTracking>
         <search>
            <requestID>testroger</requestID>
            <!--Optional:-->
            <pro>XXXXXX</pro>
         </search>
         <debug>N</debug>
      </v1:shipmentTracking>
   </soapenv:Body>
</soapenv:Envelope>

I've omitted the base 64 encoded Basic Auth information above, but I assure you I am using the exact same value in my request.

My request is below, using node.js. I should note that I am providing proxy information in my request, but I have verified that it works in other request functions.

function estes(obj) {

    var auth = 'Basic XXXXXXX'

    var url = 'https://api.estes-express.com:443/ws/estesrtshipmenttracking.base.ws.provider.soapws:EstesShipmentTracking/estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Port'

    const request = require('request')
    const fs = require('fs');
    const xml = fs.readFileSync('estessample.xml', 'utf-8');

    request.post({
        uri: url,
        headers: {
            'SOAPAction': 'estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder_shipmentTracking',
            'Content-Type': 'text/xml;charset=UTF-8',
            'Content-Length': xml.length,
            'Host': 'api.estes-express.com:443',
            'Authorization': auth
        },
        proxy: 'XXXXXX',
        body: xml
    }, function (error, response, body) {
        console.log(body)

        fs.writeFile("response.txt", body, (err) => {
            if (err) console.log(err);
            console.log("Successfully Written to File.");
        });
    })
}

This is the XML that I am posting to their service (estessample.xml), which is the same as what the Estes web services team was using that worked above:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="https://api.estes-express.com/ws/tools/shipment/tracking/v1.1/">
   <soapenv:Header/>
   <soapenv:Body>
      <v1:shipmentTracking>
         <search>
            <requestID>testroger</requestID>
            <!--Optional:-->
            <pro>XXXXXXX</pro>
         </search>
         <debug>N</debug>
      </v1:shipmentTracking>
   </soapenv:Body>
</soapenv:Envelope>

And lastly, here is the error I am receiving in response.xml:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>soapenv:Client</faultcode>
         <faultstring>[ISS.0088.9164] Access to WSDescriptor estesrtshipmenttracking.base.ws.provider.soapws:EstesShipmentTracking denied.</faultstring>
         <faultactor>http://api.estes-express.com/tools</faultactor>
         <detail>
            <webM:exception xmlns:webM="http://www.webMethods.com/2001/10/soap/encoding">
               <webM:className>com.wm.app.b2b.server.AccessException</webM:className>
               <webM:message xml:lang="">[ISS.0088.9164] Access to WSDescriptor estesrtshipmenttracking.base.ws.provider.soapws:EstesShipmentTracking denied.</webM:message>
            </webM:exception>
         </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>
dbc
  • 104,963
  • 20
  • 228
  • 340
Shane Sepac
  • 806
  • 10
  • 20
  • Any update on the existing answer? Does it help or no? – Tarun Lalwani Jul 02 '19 at 07:49
  • @TarunLalwani It did not work unfortunately. – Shane Sepac Jul 03 '19 at 15:20
  • It seems you are using a proxy here and I am doubting that it could be the one causing the issue. I would suggest you test it in an environment where no proxy is involved first – Tarun Lalwani Jul 03 '19 at 15:47
  • @TarunLalwani My proxy does work when I make requests on the same machine to other APIs though, and doesn't work when I stop using the proxy. I am sure the proxy is set up properly, but perhaps it is interfering with the request? – Shane Sepac Jul 03 '19 at 15:50
  • Do you mean SOAP APIs or normal APIs? Also, any other API on the same server was tested? Can you still test outside a proxy with direct internet just to be 100% sure. We have to use the theory of elimination – Tarun Lalwani Jul 03 '19 at 15:51

2 Answers2

1

The error is due to an authentication error. I just tried accessing the endpoint and received a similar error.

I believe you are using this node module https://github.com/request/request

After going through the code you have shared I think it might be due the way you have formed the POST request. I would suggest going through the request module documentation more thoroughly.

request.post({
    uri: url,
    headers: {
        'SOAPAction': 'estesrtshipmenttracking_base_ws_provider_soapws_EstesShipmentTracking_Binder_shipmentTracking',
        'Content-Type': 'text/xml;charset=UTF-8'
    },
    'auth': {
      'user': '<username>',
      'pass': '<password>',
    },
    body: xml,
}, function (error, response, body) {
   // Code Omitted
})

A simplified sample shown above. Take note of the auth section. The module will also take care of setting the content-length header.

Josnidhin
  • 12,469
  • 9
  • 42
  • 61
  • This did not fix the problem for me. I am using the exact code you sent me with working auth credentials... – Shane Sepac Jul 03 '19 at 15:20
  • 1
    I am not sure why it is not working. SoapUI has a free version can your try using it to make the same request. The question shows you are using some proxy if that is still the case try testing without it. – Josnidhin Jul 04 '19 at 01:14
0

After many hours spent trying to get Estes' SOAP service working on multiple networks, I could not. However, I did find a working workaround.

Create an HTTP request and POST to the following: https://myestes-api.estes-express.com/shipmenttracking/search

Then in the body of your request send the following schema and make sure to replace <MY_PRO_NUMBER> with your PRO number.

{
    "session": "",
    "type": "PRO",
    "search": "<MY_PRO_NUMBER>",
    "sort": "",
    "direction": "",
    "rowsPerPage": "25",
    "page": "1",
    "totalPages": "1"
}
Shane Sepac
  • 806
  • 10
  • 20