Category
The company I work for has hundreds of small accounting programs written many years ago in Delphi 5 where they have been maintained ever since. As a new member of the team, my primary task is to help them upgrade to newer versions of Delphi. But I also assist in supporting their legacy code for dozens of county offices that rely on them every day. Sometimes, these customers need features that, while are simple to implement in newer versions of Delphi, were not yet added to the toolset in the late 1990s. One such request came through a few months ago and I was surprised to discover that it had never been requested--nor did the rest of the team know how to handle it.
The need was to be able to import data through a SOAP webservice. I didn't learn about this until another programmer had the XML packet, complete with SOAP header he had pulled from the example sent to him, all ready packaged and ready to hand off to some other function. I knew I would be writing a DLL in Delphi 11 that would be called by his Delphi 5 application but I had never called a SOAP service from Delphi with raw XML--I had always used its WSDL importer, filled in properties and called a method of the class. As I looked further at this, trying to untangle what the end result of what I needed to do and thinking it couldn't be that hard, a thought struck me: why not try this new AI tool, ChatGPT, that others have said had been helping them with coding? I already had a free account and had used it a few times for research and to help explain a few technical things but this was a chance to see if it could actually help me save some time as a professional programmer.
So I opened up a new ChatGPT session and typed in:
How do I call a SOAP web service from Delphi without using the WSDL importer?
The response was a great explanation of the process:
Calling a SOAP web service from Delphi without using the WSDL importer involves manually crafting the SOAP request and handling the SOAP response using the Indy components (TIdHTTP) or other HTTP libraries. This approach requires a good understanding of SOAP XML structure and the HTTP protocol. Here's a basic outline of the steps you need to follow:
Create the SOAP Request XML: Manually construct the SOAP request XML using the appropriate SOAP envelope, headers, and body for your web service method. The structure of the XML depends on the specific web service you're interacting with.
Set Up the HTTP Request: Use Delphi's HTTP library (e.g., TIdHTTP from Indy) to create an HTTP POST request to the web service endpoint. Set the appropriate headers, such as "Content-Type" and "SOAPAction" header.
Send the SOAP Request: Send the SOAP request XML as the content of the HTTP POST request. Make sure to encode the request XML properly.
Receive and Process the Response: Receive the HTTP response from the server. Extract the SOAP response XML from the response body.
Parse the SOAP Response: Manually parse the SOAP response XML to extract the relevant data. This may involve using XML parsing libraries like Delphi's built-in XML components or other third-party XML parsing libraries.
Handle Errors: Implement error handling logic to deal with various possible error scenarios, both at the HTTP level and the SOAP level.
Here's a simplified example of what the code might look like using Indy's TIdHTTP component:
uses
IdHTTP, IdSSLOpenSSL;
procedure CallSoapWebService;
var
HTTPClient: TIdHTTP;
RequestXML: TStringStream;
ResponseXML: string;
EndpointURL: string;
begin
HTTPClient := TIdHTTP.Create(nil);
RequestXML := TStringStream.Create('YourSOAPRequestXMLHere', TEncoding.UTF8);
EndpointURL := 'YourWebServiceEndpointURLHere';
try
HTTPClient.Request.ContentType := 'text/xml;charset=UTF-8';
HTTPClient.Request.CustomHeaders.Add('SOAPAction: YourSOAPActionHere');
ResponseXML := HTTPClient.Post(EndpointURL, RequestXML);
// Process the SOAP response XML here
except
on E: Exception do
begin
// Handle exceptions
end;
end;
HTTPClient.Free;
RequestXML.Free;
end;Remember, this is a very basic example and may not cover all the complexities of real-world SOAP interactions. Additionally, manually dealing with SOAP can be error-prone and time-consuming, so using the WSDL importer is generally recommended for more robust and maintainable code.
I was very impressed but since I'm using Delphi 11, I wanted to know if I could use the newer internet client components instead of Indy; so, I typed this in next:
Can I do this with NetHTTPClient instead?
The sample code was reworked to use this component instead and even acknowledged it provides an easier and more modern way to work with HTTP requests and responses.
After playing around with the updated code for a bit, I noticed it had used the property DefaultHeaders
which is not part of the HTTPClient
component. I asked ChatGPT about that and it immediately apologized and reworked the code using CustomHeaders
instead (why it couldn't have used the correct property in the first place is a mystery to me):
uses System.Net.HttpClient, System.Net.URLClient, System.Classes; procedure CallSoapWebService; var HTTPClient: TNetHTTPClient; RequestContent: TStringStream; ResponseContent: string; EndpointURL: string; begin HTTPClient := TNetHTTPClient.Create(nil); RequestContent := TStringStream.Create('YourSOAPRequestXMLHere', TEncoding.UTF8); EndpointURL := 'YourWebServiceEndpointURLHere'; try HTTPClient.CustomHeaders['Content-Type'] := 'text/xml;charset=UTF-8'; HTTPClient.CustomHeaders['SOAPAction'] := 'YourSOAPActionHere'; ResponseContent := HTTPClient.Post(EndpointURL, RequestContent).ContentAsString; // Process the SOAP response XML here except on E: Exception do begin // Handle exceptions end; end; HTTPClient.Free; RequestContent.Free; end;
I asked a few more clarifying questions and got really good answers, turned the procedure into a function, added a try/finally
block around the bulk of the function to properly free the components, created an interface to convert strings to PChars to work inside the DLL (I suppose I could've asked ChatGPT to do this for me!), and ended up with a useful tool in our library to support our legacy code a little longer.
function CallSOAP(const RequestURL, RequestStr: string; var ResponseStr: string): Boolean; var RequestContent: TStringStream; begin NetHTTPClient := TNetHTTPClient.Create(nil); RequestContent := TStringStream.Create(RequestStr, TEncoding.UTF8); try Result := True; try NetHTTPClient.CustomHeaders['Content-Type'] := 'text/xml;charset=UTF-8'; ResponseStr := NetHTTPClient.Post(RequestURL, RequestContent).ContentAsString; except on E: Exception do begin ResponseStr := E.Message; Result := False; end; end; finally RequestContent.Free; end; end;
This is a really simple example of how AI can enhance programmer productivity.
My experience was a lot worse
I tried something similar several times but always got code that had some compile errors and / or was using some classes or methods that simply didn't exist. chatGPT always aplogized when I told it about these errors and generated new code, that again had the same kind of errors. After a few iterations of that I got bored and wrote the code myself.
And after trying this several times with the same kind of results, I finally gave up.
You seem to have had more luck or maybe your prompts were better than mine.
To be fair...
To be fair, I encountered a compiler error as well after I switched to NetHTTPClient
--it used DefaultHeaders
instead of CustomHeaders
but it was pretty quick to spot and fix. There may have been a couple other things as well, but the overall experience was that it increased my productivity in this instance by jump-starting the coding process--which is what I was hoping.
Add new comment