Reputation: 230
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
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