al246
al246

Reputation: 230

SOAP API call - How to insert Token

I am calling a SOAP API that returns XML and am receiving the following error

Error -

    title>401 - Unauthorized: Access is denied due to invalid credentials.</title>

I have used the information I can find on others SO queries, SOAP info and my specific calls documentation and this is my code that I have put together so far for it

String soap = 
  '''<?xml version="1.0"?>
 <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:ns1="http://thalesgroup.com/RTTI/2014-02-20/ldb/" 
 xmlns:ns2="http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard">
  <SOAP-ENV:Header>
    <ns2:AccessToken>
      <ns2:TokenValue>my_token</ns2:TokenValue>
    </ns2:AccessToken>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <ns1:GetDepartureBoardRequest>
      <ns1:numRows>10</ns1:numRows>
      <ns1:crs>MAN</ns1:crs>
    </ns1:GetDepartureBoardRequest>
  </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>''';

  // Send the POST request, with full SOAP envelope as the request body.
 http.Response response = await http.post(Uri.parse(
  'https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx'),
  headers: {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': 'http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard'
  },
  body: soap
);


var rawXmlResponse = response.body;


final parsedXml = XmlDocument.parse (rawXmlResponse);
print(parsedXml);


}

The provider of the API states in their documentation

    This token shall be passed as a SOAP Header value.

Is my inclusion in the body enough or how do I reference it in the section...

headers: {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': 'http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard'

Here is an example - https://wiki.openraildata.com/index.php/GetDepBoardWithDetails

Data from - https://realtime.nationalrail.co.uk/OpenLDBWS/

Thank you

Updated call

String soap = 
  '''
<SOAP-ENV:Envelope 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns1="http://thalesgroup.com/RTTI/2017-10-01/ldb/"
xmlns:ns2="http://thalesgroup.com/RTTI/2013-11-28/Token/ns2es">
 <SOAP-ENV:Header>
   <ns2:AccessToken>
     <ns2:TokenValue>my_token</ns2:TokenValue>
   </ns2:AccessToken>
 </SOAP-ENV:Header>
 <SOAP-ENV:Body>
   <ns1:GetDepartureBoardRequest>
     <ns1:numRows>10</ns1:numRows>
     <ns1:crs>MAN</ns1:crs>
   </ns1:GetDepartureBoardRequest>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>''';
 

  // Send the POST request, with full SOAP envelope as the request body.
 http.Response response = await http.post(Uri.parse(
  'https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01'),
  headers: {
    'SOAPAction': 'http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard'
  },
  body: soap
);

Updated response

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://thalesgroup.com/RTTI/2017-10-01/ldb/" targetNamespace="http://thalesgroup.com/RTTI/2017-10-01/ldb/">
<wsdl:import namespace="http://thalesgroup.com/RTTI/2017-10-01/ldb/" location="rtti_2017-10-01_ldb.wsdl"/>
<wsdl:service name="ldb">
  <wsdl:port name="LDBServiceSoap" binding="tns:LDBServiceSoap">
    <soap:address location="https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx"/>
  </wsdl:port>
  <wsdl:port name="LDBServiceSoap12" binding="tns:LDBServiceSoap12">
    <soap12:address location="https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx"/>
  </wsdl:port>
</wsdl:service>
</wsdl:definitions>

Which is this webpage - https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01

Upvotes: 0

Views: 2126

Answers (1)

Bogdan
Bogdan

Reputation: 24590

The correct SOAP message should look like this:

<SOAP-ENV:Envelope 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns1="http://thalesgroup.com/RTTI/2017-10-01/ldb/"
xmlns:ns2="http://thalesgroup.com/RTTI/2013-11-28/Token/ns2es">
 <SOAP-ENV:Header>
   <ns2:AccessToken>
     <ns2:TokenValue>my_token</ns2:TokenValue>
   </ns2:AccessToken>
 </SOAP-ENV:Header>
 <SOAP-ENV:Body>
   <ns1:GetDepartureBoardRequest>
     <ns1:numRows>10</ns1:numRows>
     <ns1:crs>MAN</ns1:crs>
   </ns1:GetDepartureBoardRequest>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Pay attention to the ns1 and ns2 namespaces.

Based on the documentation you posted, the WSDL to use is at https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01 and the namespaces to use based on that WSDL are the ones from the message I posted. The example you are using look older; the page is published on 18 October 2016, at 20:51, but the version parameter on the WSDL says 2017).

Before writing your code, I suggest you feed that WSDL link to SoapUI and do a few test calls until you make the call work with SoapUI. Then you can write your code to duplicate the request that SoapUI is making.

Obviously, you also need a valid token to send to the service. Since it's used for access, if you are not sending a valid one then you clearly won't get access, even if your SOAP message is properly built.

All licensed users will be issued with a token to access public web services. This token shall be passed as a SOAP Header value. The service will reject all requests with no token or an incorrect token code.

Are you a licensed user? Did you receive a token from them to use in your calls?

EDIT: after the extra details added to the question.

You are not sending your SOAP message to the correct endpoint. You need to do a POST to https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx not to https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01.

The https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01 URL just gives you the WSDL of the service, and the SOAP address inside the WSDL tells you where the endpoint of the service actually is:

<soap:address location="https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx"/>

You may want to read these also:

In regards to how you get the WSDL of a service and its endpoint, usually the convention is to use POST endpoint to invoke the service, and GET endpoint?wsdl to get the WSDL. But that's just a convention. The two things can be separated from each other, and in your case they are. You get the WSDL on one endpoint and the invocation is done on another. That's why you need to use a different endpoint.

Upvotes: 2

Related Questions