docs.intersystems.com
Home  /  Application Development: Using Adapters and Gateways in Productions  /  Adding SOAP Services and Web Clients to Productions  /  Creating a Web Service in a Production


Adding SOAP Services and Web Clients to Productions
Creating a Web Service in a Production
[Back]  [Next] 
InterSystems: The power behind what matters   
Search:  


This chapter describes how to create an production web service, which is a web service in a production. When you do this, you are providing a SOAP-enabled interface to the production. This chapter discusses the following:
For settings not listed in this book, see Settings in All Productions in Managing Productions Productions.
For an alternative approach, see the appendix Using the SOAP Inbound Adapter.”
Tip:
InterSystems IRIS™ also provides specialized business service classes that use SOAP, and one of those might be suitable for your needs. If so, no programming would be needed. See Connectivity Options in Introducing Interoperability Productions.
Overall Behavior
An production web service is based on EnsLib.SOAP.Service or a subclass. This class extends both Ens.BusinessService (so that it is a business service) and %SOAP.WebService (so that it can act as a web service as well). An production web service behaves as follows:
Communication with the outside world is done via SOAP request and response messages. InterSystems IRIS Interoperability request and response messages are used within the production.
Basic Requirements
To create a web service in a production, you create a new business service class as described here. Later, add it to your production and configure it.
You must also create appropriate message classes, if none yet exist. See Defining Messages in Developing Productions.
The following list describes the basic requirements of the business service class:
The following example shows in general what the class might look like:
Class Hospital.MyService Extends EnsLib.SOAP.Service
{

///For this business service, ADAPTER should be "" so that we use the normal SOAP processing
Parameter ADAPTER = "";

Parameter SERVICENAME = "MyService";

Parameter NAMESPACE = "http://www.myhospital.org";

Parameter USECLASSNAMESPACES = 1;

Method GetAuthorization(patientID As %Integer, RequestedOperation As %String, 
LikelyOutcome As %String) As %Status [ WebMethod ]
{
    set request = ##class(Hospital.OperateRequest).%New()
    set request.PatientID = patientID
    set request.RequestedOperation = RequestedOperation
    set request.LikelyOutcome = LikelyOutcome
    set tSC=..SendRequestSync("Hospital.PermissionToOperateProcess",request,.response)
    // Create the SOAP response, set its properties, and return it.
}

}
Defining Web Methods for Use in InterSystems IRIS
This section describes the basic requirements for an InterSystems IRIS web method.
Important:
In most cases, web methods should be instance methods. Within a web method, it is often necessary to set properties of and invoke methods of the web service instance to fine-tune the behavior of the method. Because a class method cannot do these tasks, a class method is usually not suitable as a web method.
For additional notes, see Basic Requirements in the chapter Creating Web Services in Creating Web Services and Web Clients.
Basic Steps of an InterSystems IRIS Interoperability Web Method
Within a production web service, a web method should generally do the following:
  1. Create a request message and set its properties with information from the inbound SOAP message.
  2. Call a suitable method of the business service to send the request to a destination within the production. Specifically, call SendRequestSync(), SendRequestAsync(), or (less common) SendDeferredResponse(). For details, see Sending Request Messages in Developing Productions
    Each of these methods returns a status (specifically, an instance of %Status).
  3. Check the status returned from the previous step and react appropriately.
  4. Then:
Returning Faults to the Caller
By default, if an error occurs when a web method runs, the web service returns a SOAP message to the caller, but this message does not indicate where precisely the fault occurred. An example follows:
  <SOAP-ENV:Body>
   <SOAP-ENV:Fault>
    <faultcode>SOAP-ENV:Server</faultcode>
    <faultstring>Server Application Error</faultstring>
   <detail>
      <error xmlns='http://www.myapp.org' >
        <text>ERROR #5002: ObjectScript error: <INVALID OREF>
            zGetCustomerInfo+10^ESOAP.WebService.1</text>
      </error>
   </detail>
   </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
Your web methods should check for an error and use ReturnMethodStatusFault() or ReturnStatusFault(). In case of error, the message will be more informative, as follows:
  <SOAP-ENV:Body>
   <SOAP-ENV:Fault>
    <faultcode>SOAP-ENV:Method</faultcode>
    <faultstring>Server Application Error</faultstring>
    <faultactor>ESOAP.WebService</faultactor>
    <detail>
      <error xmlns='http://www.myapp.org' >
       <text>ERROR <Ens>ErrException:
             <DIVIDE>zGetCustomerRequest+8^ESOAP.MyOperation.1 -
             logged as '13 Jul 2007' number 4 @'    set x=100/0'</text>
     </error>
   </detail>
   </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
The ReturnMethodStatusFault() and ReturnStatusFault() methods return a SOAP fault to the caller and then generate an exception which will create an alert (depending on settings). These methods have the following signatures:
ClassMethod ReturnStatusFault(pCode As %String,
                              pStatus As %Status)

ClassMethod ReturnMethodStatusFault(pStatus As %Status)
Here:
Also notice that these methods set the <faultactor> element of the SOAP fault.
Example
The following shows a simple example:
Method GetCustomerInfo(ID As %Numeric) As ESOAP.SOAPResponse [WebMethod]
{
    //create request message with given ID
    set request=##class(ESOAP.CustomerRequest).%New()
    set request.CustomerID=ID

    //send request message 
    set sc= ..SendRequestSync("GetCustomerInfoBO",request,.response)
    if $$$ISERR(sc) do ..ReturnMethodStatusFault(sc)

    //use info from InterSystems IRIS response to create SOAP response
    set soapresponse=##class(ESOAP.SOAPResponse).%New()
    set soapresponse.CustomerID=response.CustomerID
    set soapresponse.Name=response.Name
    set soapresponse.Street=response.Street
    set soapresponse.City=response.City
    set soapresponse.State=response.State
    set soapresponse.Zip=response.Zip

    quit soapresponse
}
Viewing the WSDL
InterSystems IRIS automatically creates and publishes a WSDL document that describes your production web service. Whenever you modify and recompile the web service, InterSystems IRIS automatically updates the WSDL correspondingly.
To view the WSDL for the web service, use the following URL:
base/app-name/web_serv.cls?WSDL
Here base is the base URL for your web server (including port if necessary), /csp/app is the name of the CSP application in which the web service resides, and web_serv is the class name of the web service. (Typically, /csp/app is /csp/namespace, where namespace is the namespace that contains the CSP application and the production. )
For example:
http://localhost:52773/csp/samples/MyApp.StockService.cls?WSDL
The browser displays the WSDL document as an XML document. The following shows an example:
Web Service Example
The following simple example shows a production web service that can be used to look up customer information, given a customer ID.
Class ESOAP.WebService Extends EnsLib.SOAP.Service
{

Parameter ADAPTER;

Parameter NAMESPACE = "http://www.myapp.org";

Parameter SERVICENAME = "CustomerLookupService";

Method GetCustomerInfo(ID As %Numeric) As ESOAP.SOAPResponse [WebMethod]
{
    //create request message with given ID
    set request=##class(ESOAP.CustomerRequest).%New()
    set request.CustomerID=ID

    //send request message 
    set sc= ..SendRequestSync("GetCustomerInfoBO",request,.response)
    if $$$ISERR(sc) do ..ReturnMethodStatusFault(sc)

    //use info from InterSystems IRIS response to create SOAP response
    set soapresponse=##class(ESOAP.SOAPResponse).%New()
    set soapresponse.CustomerID=response.CustomerID
    set soapresponse.Name=response.Name
    set soapresponse.Street=response.Street
    set soapresponse.City=response.City
    set soapresponse.State=response.State
    set soapresponse.Zip=response.Zip

    quit soapresponse
}

}
The SOAP response class is as follows:
///
Class ESOAP.SOAPResponse Extends (%RegisteredObject, %XML.Adaptor)
{

Property CustomerID As %Numeric;
Property Name As %String;
Property Street As %String;
Property City As %String;
Property State As %String;
Property Zip As %Numeric;

}
Note the following points:
Enabling SOAP Sessions
The SOAP specification does not include session support. However, it is often useful to maintain a session between a web client and the web service that it uses. You can do this with a production web service. If a web service uses sessions, it establishes a session ID and allows repeated calls on the service after one successfully authenticated call from a client.
Support for SOAP sessions is controlled by the SOAPSESSION class parameter. The default is 0, which means that the web service does not use sessions.
To enable SOAP sessions, create a subclass of EnsLib.SOAP.Service and set SOAPSESSION to 1 in the subclass. Base your production web service on this subclass.
For more information on SOAP sessions, see Creating Web Services and Web Clients in the documentation.
Additional Options
Because your production web service extends %SOAP.WebService, you can use all the SOAP support provided by that class. This support includes options for the following customizations, among others:
For these options and others, see Creating Web Services and Web Clients in the documentation set.
Adding and Configuring the Web Service
To add your production web service (a business service) to a production, use the Management Portal to do the following:
  1. Add an instance of your custom class to the production.
    Important:
    Ensure that the configuration name is the same as the full class name, including package. This is a requirement for running a production web service.
  2. Enable the business service.
  3. Set the Pool Size setting to 0.
    For other settings, see Configuring Productions.
  4. Run the production.