Creating Web Services and Web Clients
Creating Web Clients
|
|
A web client is software that accesses a web service. A web client provides a set of proxy methods, each of which corresponds to a method of the web service. A proxy method uses the same signature as the web service method to which it corresponds, and it invokes the web service method when asked to do so. This chapter describes how to create and use web clients in InterSystems IRIS:
Note:
For an InterSystems IRIS web service, the automatically generated WSDL might not include information about the SOAP header elements:
-
-
If you add WS-Security header elements by setting the
SecurityOut property (as described in
Securing Web Services), the WSDL does not include all needed information. (This is because the WSDL is generated at compile time and the headers are added later, at runtime.) In this case, save the WSDL to a file and edit it manually as needed.
For many reasons, it is simpler and easier to add WS-Security elements by using WS-Policy, as described in the same book. With WS-Policy, the generated WSDL includes all needed information.
-
In other cases, the generated WSDL includes all needed information.
Note that the W3C specifications do not require a web service to provide a generated WSDL.
To create an InterSystems IRIS web client, you can use the
SOAP Wizard in Studio or
the corresponding class method provided by InterSystems IRIS. In either case, the input is a WSDL document. The tools generate a web client class and all needed supporting classes.
You can provide either the URL or the file path for the WSDL.
Note:
If the WSDL indicates support for both SOAP 1.1 and SOAP 1.2, then the SOAP Wizard generates two sets of classes, if needed.
Studio provides the SOAP Wizard, which enables you to generate a client for a given web service, given the WSDL of that service.
-
Examine the WSDL and check for the following items:
-
Do the
<message> elements contain multiple parts?
-
Do the types used by the response messages belong to multiple namespaces?
-
-
-
Click either
URL or
FILE, depending on the location of the WSDL.
-
Enter the location of the WSDL. Type either the entire URL or the complete path and filename for the WSDL.
-
Important:
This wizard specifies an SSL configuration to use when accessing the WSDL. This field is not used in any other way.
-
If the WSDL is at a location that uses SSL, the wizard will (by default) checks whether the certificate server name matches the DNS name used to connect to the server. If these names do not match, the connection is not permitted. This default behavior prevents
“man in the middle” attacks and is described in RFC 2818, section 3.1; also see
RFC 2595, section 2.4.
-
The wizard then attempts to access the WSDL and display it so that you can verify that you have chosen the correct one.
If the wizard cannot access the WSDL, it displays a screen that displays the error and provides options that you can use to provide a username and password. (Many WSDLs are at URLs that are protected by a username and password, and this is a common reason for failing to access the WSDL.) In this scenario, first do one of the following:
Then enter values in the
Username and
Username fields and press
Try Again. Note that the wizard does not save your entries for these items.
-
On the screen that displays the WSDL, specify options as follows:
-
-
-
-
Compile flags Specify flags to control how the compiler behaves. To get information about the compiler flags, execute the following command:
Do $System.OBJ.ShowFlags()
-
Class Type Choose a type to use for the generated type classes:
-
If you modify the generated classes, be sure to modify the
%OnDelete() callback method as needed.
-
Proxy Class Package Type a package name for the web client. This is also used as the base package for any generated type classes. The default package name is the service name.
If this package is the same as an existing package, by default the tool overwrites any existing classes that have the same name.
-
If you are creating these classes for use in a production, optionally provide values for the following additional fields:
-
Click
Next. The wizard then displays a screen like the following:
-
Specify the following options:
-
-
If the WSDL explicitly indicates the namespace to which a given type belongs,
Add NAMESPACE Class Parameter is selected and grayed out. In this case, the generated type class will include the
NAMESPACE class parameter set equal to that namespace.
-
If you select this option, the generated type class will include the
NAMESPACE class parameter set equal to the namespace of the web service.
If you clear this option, the generated type class will not include the
NAMESPACE class parameter.
-
Important:
If the WSDL that you are using contains
<message> elements with multiple parts, be sure to select this option. If you do not, the wizard fails and displays a message like the following:
ERROR #6425: Element 'wsdl:binding:operation:msg:input' - message 'AddSoapOut'
Message Style must be used for document style message with 2 or more parts.
Similarly, if the types used by the response messages are in different namespaces than each other, be sure to select this option.
-
-
This option applies to each property that corresponds to an XML element that is specified with
nillable="true". If you select this option, the wizard adds
XMLNIL=1 to the property definition. Otherwise, it does not add this parameter.
-
-
-
-
-
-
Optionally edit the package names. The wizard uses the following rules for package names:
-
The packages specified in
Web Client Package or
Web Service Package contain the main generated web client or web service class. These values are initialized by your entry in the previous page of the wizard.
-
If the wizard generates a policy class as well (because the WSDL contains WS-Policy information), that class is in the same package by default. To specify a different package, specify a value for
Configuration Sub-Package.
By default, the class name is the web client or service name, with
Config appended to it. If you specify a value for
Configuration Sub-Package, then this generated class has the same name as the web client or service (but is in the given subpackage instead).
-
For any supporting classes that are generated, the wizard detects all the namespaces used in the WSDL. By default, it organizes the generated classes into packages, with one package for each namespace.
Optionally edit these package names.
-
Click
Next. The wizard generates and compiles the classes and displays a list of these classes.
-
Tip:
If you use a WSDL URL and there are problems with the wizard, save the WSDL as a file and try again, using that file as input.
If the WSDL contains references to externally defined entities, the wizard attempts to resolve those; for this task, the timeout period is 10 seconds.
For properties of these classes, if the corresponding element in the schema has a name that starts with an underscore (
_), the name of the property starts with a percent sign (
%).
The resulting generated classes and their organization may not be the same as if you used the SOAP wizard, which provides greater control over the packages for the generated classes.
To generate the client classes programmatically:
-
-
-
-
-
-
Invoke the
Process() method of your instance:
method Process(pLocationURL As %String, pPackage As %String = "") as %Status
-
pLocationURL must be the URL of the WSDL of the web service or the name of the WSDL file (including its complete path). Depending on the configuration of the web service, it may be necessary to append a string that provides a suitable username and password; see the examples.
-
pPackage is the name of the package in which to place the generated classes. If you do not specify a package, InterSystems IRIS uses the service name as the package name.
Note:
If this package is the same as an existing package, by default the tool overwrites any existing classes that have the same name. To prevent the tool from overwriting a class definition, add the following to that class definition:
Parameter XMLKEEPCLASS = 1;
The following shows an example Terminal session:
set r=##class(%SOAP.WSDL.Reader).%New()
GSOAP>set url="http://localhost:52773/csp/gsop/GSOP.AddComplexWS.CLS?WSDL=1"
GSOAP>d r.Process(url)
Compilation started on 11/09/2009 12:53:52 with qualifiers 'dk'
Compiling class AddComplex.ns2.ComplexNumber
Compiling routine AddComplex.ns2.ComplexNumber.1
Compilation finished successfully in 0.170s.
Compilation started on 11/09/2009 12:53:52 with qualifiers 'dk'
Compiling class AddComplex.AddComplexSoap
Compiling routine AddComplex.AddComplexSoap.1
Compiling class AddComplex.AddComplexSoap.Add
Compiling routine AddComplex.AddComplexSoap.Add.1
Compilation finished successfully in 0.363s.
In all cases, it is also possible to retrieve the WSDL from a browser after supplying the required username and password, save it as a file, and use the file instead.
After you generate an InterSystems IRIS web client class, you do not usually edit the class. Instead you write code that creates an instance of the web client and that provides provide client-side error handling. This section documents the notable exceptions where you do modify the generated client class.
Note:
Do not create a subclass of the generated web client class. The compiler will not generate the supporting classes that it would need in order to run properly, and your subclass would not be usable.
In rare cases, you might need to edit the generated client class to accommodate extremely long strings or binary values values whose lengths exceed the
string length limit.
When the SOAP Wizard reads a WSDL, it assumes that any string-type input or output can be represented in InterSystems IRIS as
%String, which is not always true. In rare cases, a string might exceed the
string length limit. Similarly, the wizard assumes that any input or output with XML type base64Binary can be represented in InterSystems IRIS as
%xsd.base64Binary), which is not always true, due to the same string length limitation. In neither case does the WSDL contain any information to indicate that this input or output could exceed the string length limit.
When your web client encounters a string or a binary value that is too long, it throws one of the following errors:
-
-
A datatype validation error:
ERROR #6232: Datatype validation failed for tag your_method_name ...
(This error, of course, can also be caused by a datatype mismatch.)
The problem, however, is easy to correct: adjust the method signature in your generated web client class (specifically the class that inherits from
%SOAP.WebClient) to use an appropriate stream class:
For example, consider a web service (
MyGiantStringService) that has one method (
WriteIt), which takes no arguments and returns a very long string. If you use the SOAP Wizard to generate the web client class, the web client class originally looks something like this:
Class GetGiantString.MyServiceSoap Extends %SOAP.WebClient
{
Method WriteIt() As %String
[Final,SoapBindingStyle=document,SoapBodyUse=literal,WebMethod]
{
Quit ..WebMethod("WriteIt").Invoke($this,"http://tempuri.org/MyApp.MyGiantStringService.WriteIt")
}
}
In this case, there is only one adjustment to make. Change the return type of
WriteIt as follows:
Method WriteIt() As %GlobalCharacterStream
[Final,SoapBindingStyle=document,SoapBodyUse=literal,WebMethod]
{
Quit ..WebMethod("WriteIt").Invoke($this,"http://tempuri.org/MyApp.MyGiantStringService.WriteIt")
}
When you compile this class, the system automatically regenerates the associated classes as needed.
If the WSDL does not specify the location of the web service, the SOAP Wizard does not specify the
LOCATION parameter of the web client. This is a rare scenario. In this scenario, edit the web client class to include the
LOCATION parameter. For example:
Parameter LOCATION = "http://localhost:52773/csp/gsop/GSOP.AddComplexWS.cls";
Or specify the
Location property of your web client instance as shown
later in this chapter.
As noted in the
previous section, after you generate an InterSystems IRIS web client class, you do not usually edit the generated class. Instead you write code that creates an instance of that web client and that provides provide client-side error handling. In this code, do the following:
-
Create an instance of the web client class.
-
Set its properties. Here you can control items such as the following:
-
Endpoint of the web client (the URL of the web service it uses). To control this, set the
Location property, which overrides the
LOCATION parameter of the web client class.
-
Settings that designate a proxy server.
-
Settings that control HTTP Basic authentication.
-
Invoke the methods of the web client as needed.
-
-
The following shows a simple example, from a session in the Terminal:
GSOAP>set client=##class(Proxies.CustomerLookupServiceSoap).%New()
GSOAP>set resp=client.GetCustomerInfo("137")
GSOAP>w resp
11@Proxies.CustomerResponse
GSOAP>w resp.Name
Smith,Maria
In this example, we create a wrapper class for a web client that uses wrapped messages. To use the example
GSOAPClient.AddComplex.AddComplexSoap shown previously, we could create a class like the following:
Class GSOAPClient.AddComplex.UseClient Extends %RegisteredObject
{
ClassMethod Add(arg1 As ComplexNumber, arg2 As ComplexNumber) As ComplexNumber
{
Set client=##class(AddComplexSoap).%New()
//uncomment the following to enable tracing
//set client.Location="http://localhost:8080/csp/gsop/GSOP.AddComplexWS.cls"
Set ans=client.Add(arg1,arg2)
Quit ans
}
}
The client application would invoke this method in order to execute the web method.
In this example, we create a wrapper class for a web client that uses unwrapped messages. To use the example
GSOAPClient.AddComplex.AddComplexSoap shown previously, we could create a class like the following:
Class GSOAPClient.AddComplexUnwrapped.UseClient Extends %RegisteredObject
{
ClassMethod Add(arg1 As GSOAPClient.AddComplexUnwrapped.s0.ComplexNumber,
arg2 As GSOAPClient.AddComplexUnwrapped.s0.ComplexNumber)
As GSOAPClient.AddComplexUnwrapped.s0.ComplexNumber
{
//create the Add message
Set addmessage=##class(GSOAPClient.AddComplexUnwrapped.s0.Add).%New()
Set addmessage.a = arg1
Set addmessage.b = arg2
Set client=##class(AddComplexSoap).%New()
//send the Add message to client and get response
Set addresponse=client.Add(addmessage)
//get the result from the response message
Set ans=addresponse.AddResult
Quit ans
}
}
The method has the signature that would typically be expected; that is, it accepts two complex numbers and returns a complex number. The method creates the message that the web client expects. The elements of this message are the two complex numbers.
As you can see, when the web client uses unwrapped messages, it is necessary to write slightly more code to convert arguments in a user-friendly form into the message used by the web client.
When you use an instance of your web client classes, you can specify properties of that instance to control its behavior. This section discusses the properties that are most commonly set, as well as their default values.
The SOAP Wizard automatically sets the endpoint for the web client by setting the
LOCATION parameter of the web client. By default, it sets this parameter equal to the URL of the web service with which it communicates.
To override this, set the
Location property of your web client instance. If
Location is null, then the
LOCATION parameter is used.
A common usage is to set the
Location property to use a different port, in order to enable tracing. For example, suppose that in the generated web client class, the endpoint is defined as follows:
Parameter LOCATION = "http://localhost:52773/csp/gsop/GSOP.AddComplexWS.cls";
When you use this client, you can include the following line:
Set client.Location="http://localhost:8080/csp/gsop/GSOP.AddComplexWS.cls"
Note:
If the WSDL does not specify the location of the web service, the SOAP Wizard does not specify the
LOCATION parameter of the web client. This is a rare scenario. In this scenario, either edit the web client class to include the
LOCATION parameter or specify the
Location property of your web client instance as shown here.
If the endpoint for a web client has HTTPS protocol, the web client must be configured to use SSL. Specifically:
-
-
Set the
SSLConfiguration property of the web client equal to that SSL/TLS configuration name.
Note that if the client is connecting via a proxy server, you must also set the
HttpProxySSLConnect property equal to 1 in the web client. For information on configuring an InterSystems IRIS web client to use a proxy server, see the chapter
“Fine-Tuning the Web Client.”
The SOAP Wizard automatically specifies the SOAP version to use in request messages, based on the SOAP version in the WSDL of the web service. Specifically it sets the
SOAPVERSION parameter.
To override this, set the
SoapVersion property of your web client instance. Use one of the following values:
-
"" The client sends SOAP 1.1 messages.
-
"1.1" The client sends SOAP 1.1 messages.
-
"1.2" The client sends SOAP 1.2 messages.
By default, when you invoke a web client method, you do so via HTTP. The HTTP response is then available as the
HttpResponse property of the web client instance. This property is an instance of
%Net.HttpResponse, which in turn has properties like the following:
-
Headers contains the headers of the HTTP response.
-
Data is an InterSystems IRIS multidimensional array that contains any data in the HTTP response.
-
Content Date/Time: 2019-02-22 00:52:40