Introduction
WebRatio provides all the necessary features for both publishing and interrogating a Web Service. The W3C defines a Web Service as "a software system designed to support interoperable Machine to Machine interaction over a network." Web Services are frequently just Web APIs that can be accessed over a network, such as the Internet, and executed on a remote system hosting the requested services.
The W3C Web Service definition encompasses many different systems, but in common usage the term refers to clients and servers that communicate using XML messages that follow the SOAP standard. Common in both the field and the terminology is the assumption that there is also a machine readable description of the operations supported by the server written in the Web Services Description Language (WSDL). The latter is not a requirement of a SOAP endpoint, but it is a prerequisite for automated client-side code generation in the mainstream Java and .NET SOAP frameworks. The specifications that define Web Services are intentionally modular, and as a result there is no one document that contains them all. Additionally, there is neither a single, nor a stable set of specifications. There are a few "core" specifications that are supplemented by others as the circumstances and choice of technology dictate.
WebRatio adopts the SOAP specification. It's composed of an XML-based, extensible message envelope format with "bindings" to underlying protocols. The primary protocols are HTTP and HTTPS, although bindings for others, including SMTP and XMPP, have been written. When you publish a Web Service using WebRatio, the tool automatically generates the Web Service description in WSDL (Web Services Description Language). This is an XML format that allows service interfaces to be described along with the details of their bindings to specific protocols. Typically it is used to generate server and client code, and for configuration.
Publishing a Web Service
You can use the Acme Sample project to develop the Web Service example. If you do not have the Acme project in your workspace you can easily download it using the Help > WebRatio Samples command. The following figure present the complete model of a Web Service. This Web Service retrieves all the products in the database and send them as the response to the Web application that invoked the service.
To get this result you have to:
- add a Service View to your project. A Service View represents an entire Web Service. If you want to publish different Web Services you have to add different Service Views to your Web project.
- add a Port (
) to the Service View. A Web Service can have different ports, which represents a Web Service Operations container.
- add a Solicit Unit (
), which represents the entry point to the Web Service Operation: it is the start poin for each Web service.
- add a XML Out Unit (
), which extracts from the database all the products and produces an XML document. In order to retrieve the information, you have to specify an XML Out Entity (in this case "Product") on the unit. This property indicates which is the entity from which the unit has to retrieve the data. To do this you can right click on the unit and choose the Add XML Out Entity command from the context menu. Choose the entity from which you want to retrieve the data and check the Use Names property in the Properties View.
- add a Response Unit(
), which retrieves the XML document provided by the XML Out Unit and send it back to the Web application that invoked the Web Service. You have to define at least one parameter for the unit. The parameters are containers for the XML Out Unit results. To add a parameter you have to right click on the unit and select the Add Parameter. command from the context menu. In the Properties View you have to type a name for the parameter. Optionally you can define the XSD Type of the parameter. You have two different choices. You can choose one of the XML simple types if the XML Schema property is not defined. Otherwise it is either an element or a complex type of the XML SCHEMA you set in the XSL Schema property selecting an .xsd file. The .xsd file has to be placed in the "WebContent/WEB-INF/descr" folder in your Web project.
The XML Schema and the Type property are used only in the WSDL description of the Web Service. In this case the SOAP response message looks like the following
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<getAllProductsResponse>
<Root>
<Product id="ent1">
<Instance>
<price id="att11">1500.0</price>
<highlighted id="att23">false</highlighted>
<name id="att10">Wilderness</name>
<thumbnail id="att12" blob="upload/small_chair_5.jpg"/>
<description id="att9">Stainless steel meets crystal and silk to make the comfort and look.</description>
<code id="att8">5125</code>
<OID id="attN2F94A6">1</OID>
</Instance>
<Instance>
<price id="att11">124.0</price>
<highlighted id="att23">false</highlighted>
<name id="att10">Blue Fountain</name>
<thumbnail id="att12" blob="upload/small_lamp_5.jpg"/>
<description id="att9">A marvellous lamp shedding a new light to your family life.</description>
<code id="att8">3456</code>
<OID id="attN2F94A6">2</OID>
</Instance>
</Product>
</Root>
</getAllProductsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
- add a Error Response Unit (
), which intercepts all the errors that one of the previous unit can throw. This unit notifies the invoking Web application with a SOAP Fault message that looks loke the following
<SOAP-ENV:Envelope
xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'
SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:v='http://www.eggheadcafe.com/webservices/'>;
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>Client</faultcode>
<faultstring>Unable to execute the operation</faultstring>
<detail>
<message>exception stack trace</message>
<errorcode>error code</errorcode>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The Solicit Unit can have parameters. This is due to the fact that you can specify attribute, key and relationship-role conditions on the XML Out Entity of the following XML Out Unit. Let's see an example. This Web Service retrieves all the product having as minimum price the value obtained from the Solicit Unit parameter.
The differences respect the previous example are:
- the Solicit Unit must have a parameter representing the minimum price. To add a parameter you have to right click on the unit and select the Add Parameter.. command from the context menu.
- the XML Out Unit must have an attribute condition on the XML Out Entity expressing that the product price has to be greater than the input parameter value.
You may want to change the formatting of the XML Document provided by the XML Out Unit. You have to use the Adapter Unit (
) to convert the original XML Document in another XML document. The following Web Service show an example of the Adaper Unit usage.
The Adapter Unit must be placed between the XML Out Unit and the Response Unit. You have to add an XSL file to the unit. The XSL file is necessary to specify how to convert the original XML Document in another XML Document having the desired formatting. To add a XSL file to the unit you have to click on the button next to the XSL File field in the Properties View. The file has to be place din the "WebContent/WEB-INF/descr" folder in your Web project.
The Adapter Unit also permits to process many input XML Documents at the same time. The unit takes all the input documents and merges them in an unique document. In this case the XSL code you have to write to transform the document has to consider the XML document after the merge operation. To specify that the unit uses many input document you have to type the number of documents in the Nr. of Input Document field in the Properties View.
REST Invocation
It's possible to publish a Web Service that does not use the SOAP messages but the REST style invocation. Please refer to this link for more information about REST. To change the invocation style on a modeled Web Service is necessary to change a property of the Solicit Unit.
- Select the Solicit Unit
- In the Properties View, choose the Invocation Style property and select the "REST" option.
- Generate the Web Project
In order to simulate the invocation of the Web Service, it's possible to point the browser to the following URL
http://localhost:8080/AcmeWS/WS_Publish/Operations/getProductsByName.do?keyword=Allair
This URL is composed by
http://<host>:<port>/<webApplication>/<ServiceViewName>/<PortName>/<SolicitName>.do?
<SolicitParameterName1>=<value1>&<SolicitParameterName2>=<value2>
The response is the following:
<m:getProductsByNameResponse>
<Root>
<Product id="ent1">
<Instance>
<price id="att11">4550.0</price>
<highlighted id="att23">false</highlighted>
<name id="att10">Allair</name>
<thumbnail id="att12" blob="upload/small_chair_2.jpg"></thumbnail>
<description id="att9">
Brighten up your living room with warmly illuminating ideas.
</description>
<code id="att8">5127</code>
<OID id="attN2F94A6">3</OID>
</Instance>
</Product>
</Root>
</m:getProductsByNameResponse>
Note that there are no more the SOAP:Envelope and SOAP:Body tags.
The WSDL Web Service Description
WebRatio automatically generates the WSDL description of the Web Service you model in your Web project. You can see this description directly from the generated web application using the "wsdl.do" action. Here it is a sample WSDL description related to the examples shown previously.
- Line 4-41. The XML Schema specification of data types is provided. This code is copied from the .xsd files you have specified on the Solicit Unit and Response Unit parameters.
- For each Web Service Operation there is the declaration of two messages: the request and the response message.
- Line 44-49. The messages for the getAllProduct operation
- Line 50-55. The messages for the getProductsByPrice operation
- Line 58-67. The IFML model containing the port and two Web Service Operation is described. For each operation there is its name and the input and output messages.
- Line 70-90. Declaration of the SOAP messages.
- Line 91-97. Declaration of the Web Service ports.
<definitions name="WebRatio" targetNamespace="http://www.IFML.org/webservices/wsdl">
<types>
<xsd:schema targetNamespace="http://www.IFML.org/webservices/wsdl/prices">
<xsd:complexType name="pricesType">
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="min-price" type="xsd:string"/>
<xsd:element minOccurs="1" maxOccurs="1" name="max-price" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<xsd:schema targetNamespace="http://www.IFML.org/webservices/wsdl/products">
<xsd:complexType name="productsType">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="unbounded" name="Product">
<xsd:complexType>
<xsd:element minOccurs="1" maxOccurs="1" name="id" type="xsd:int"/>
<xsd:element minOccurs="0" maxOccurs="1" name="code" type="xsd:int"/>
<xsd:element minOccurs="0" maxOccurs="1" name="description" type="xsd:string"/>
<xsd:element minOccurs="0" maxOccurs="1" name="name" type="xsd:string"/>
<xsd:element minOccurs="0" maxOccurs="1" name="price" type="xsd:float"/>
<xsd:element minOccurs="0" maxOccurs="1" name="thumbnail" type="xsd:string"/>
<xsd:element minOccurs="0" maxOccurs="1" name="highlighted" type="xsd:boolean"/>
<xsd:element minOccurs="0" maxOccurs="unbounded" name="Combination">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="1" maxOccurs="1" name="id" type="xsd:int"/>
<xsd:element minOccurs="0" maxOccurs="1" name="code" type="xsd:int"/>
<xsd:element minOccurs="0" maxOccurs="1" name="description" type="xsd:string"/>
<xsd:element minOccurs="0" maxOccurs="1" name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</types>
<message name="getAllProductsIN">
<part name="Parameter3" type="xsd:string"/>
</message>
<message name="getAllProductsResponse">
<part name="Products" type="rsp3:productsType"/>
</message>
<message name="getProductsByPriceIN">
<part name="min-price" type="slp15:"/>
</message>
<message name="getProductsByPriceResponse">
<part name="Products" type="rsp3:productsType"/>
</message>
<portType name="Operations_PortType">
<operation name="getAllProducts">
<input message="tns:getAllProductsIN"/>
<output message="tns:getAllProductsResponse"/>
</operation>
<operation name="getProductsByPrice">
<input message="tns:getProductsByPriceIN"/>
<output message="tns:getProductsByPriceResponse"/>
</operation>
</portType>
<binding name="Operations" type="tns:Operations_PortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getAllProducts">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal" namespace=""/>
</input>
<output>
<soap:body use="literal" namespace=""/>
</output>
</operation>
<operation name="getProductsByPrice">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal" namespace="http://www.IFML.org/webservices"/>
</input>
<output>
<soap:body use="literal" namespace="http://www.IFML.org/webservices"/>
</output>
</operation>
</binding>
<service name="WS_Publish">
<port binding="tns:Operations" name="Operations_Port">
<soap:address location="http://localhost:8080/AcmeWS/WS_Publish/Operations.do"/>
</port>
</service>
</definitions>
Invoking a Web Service
You can model a Web Service request from your Web project. You have not to use a Service View. Service Views are only for Web Service publishment. You have to model the request in a Site View. In this example you are going to invoke a Web Service that convert Celsius degrees to Fahrenheit degrees (Visual DataFlex Web Service for Temperature Conversions).
The first thing you have to do is to retrieve the information about the Web Server you are going to invoke. Here is the list of the necessary information in this case:
<m:CelciusToFahrenheitResponse xmlns="http://webservices.daehosting.com/temperature">
<m:CelciusToFahrenheitResult>conversionResult</m:CelciusToFahrenheitResult>
</m:CelciusToFahrenheitResponse>
Let's see how to model the Web Service request in the Site View of your Web project. The following figure shows the complete model.
- add a Entry Unit with two fields: one field for entering the Celsius temperature to convert and one field to see the correspondent Fahrenheit temperature.
- add a Request Response Unit (
). In the Properties View, set all the Web Service properties listed above. To set the input parameter for the request, you have to add a parameter to the unit. To do this right click on the unit and choose the Add Request Parameter.. command from the context menu. The parameter name must be the same requests by the Web Server specification. The Namespace URI has to be set only if you have set it for the Request Response Unit. The last thing is to specify the XSL File in the Output Trasformation property. The XSL file has to be placed in the "WebContent/WEB-INF/descr" folder in your Web project.
|
 |
The XSL file must contain the code for transforming the SOAP response message to another formatting that allows the Request Response Unit to expose a output parameter bringing the Farenheit temperature. The output parameter are retrieved from the output XSL transformation file, if specified; an output parameter named myParam is declared in the XSL document by adding to the <xsl:stylesheet> element a direct child element: <out:output-param name="myParam"/> where the prefix out must be associated with the following namespace URI: http://www.IFML.org/webservices/output At run-time the output of the XSL transformation is analyzed, at any level, to find occurrences of the same element (<out:output-param>), but enriched with the XML attribute value, to define the run-time values of the associated unit's output parameter. So, the XSL code has to:
- declare the namespace related to the Namespace URI if it is used by the Request Response Unit (line 8)
- declare the output parameter (line 11)
- construct the XML code containing the output parameter and its value (line 14-16)
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:w="http://www.IFML.org/webservices"
xmlns:out="http://www.IFML.org/webservices/output"
xmlns:m="http://webservices.daehosting.com/temperature"
version="1.0">
<out:output-param name="Fahrenheit"/>
<xsl:template match="//m:CelciusToFahrenheitResponse">
<result>
<out:output-param name="Fahrenheit" value="{m:CelciusToFahrenheitResult/text()}"/>
</result>
</xsl:template>
</xsl:stylesheet>
At this point the IFML model is complete. You can generate your application and test the Web Service request. The Web application send a SOAP request message to the Web Server like the following
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<m:CelciusToFahrenheit xmlns:m="http://webservices.daehosting.com/temperature">
<m:nCelcius>10</m:nCelcius>
</m:CelciusToFahrenheit>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
and the Web Service answers with a SOAP response message like the following
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<m:CelciusToFahrenheitResponse xmlns:m="http://webservices.daehosting.com/temperature">
<m:CelciusToFahrenheitResult>50</m:CelciusToFahrenheitResult>
</m:CelciusToFahrenheitResponse>
</soap:Body>
</soap:Envelope>
Adding the SOAP:Header section
It's possible to define the soap:header section of a SOAP request using the Input Transformation Property of the Request Response Unit.
For example it's possible to use the soap:header section in order to assure integrity and confidentiality to SOAP messages. The WS-Security extension to the Web Service specification has this goal (you can find more information about this topic reading this article). This protocol states that all the additional information must be contained in the soap:Header section of the SOAP request. This is an example:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://examples.webratio.com/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-32392973" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>ABCDE</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypassword</wsse:Password>
<wsse:Nonce>t2xCiUy6KLUs3FngzyYpgw==</wsse:Nonce>
<wsu:Created>2007-12-31T10:00:00.000Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<pj:getProject>
<projectCode>Test</projectCode>
</pj:getProject>
</soapenv:Body>
</soapenv:Envelope>
In order to build the correct SOAP message using the Request Response Unit it's necessary to accomplish these steps:
- In the Properties View, set the "Input Type" property of the Request Response Unit to "Document"
- Choose the "Input Transformation" property and create a new template file (e.g. WSSE_SOAP_Request.xml.template)
- Write in this template file all the code necessary in order to build the entire SOAP message. This is a sample code:
#?delimiters [%, %], [%=, %]
<wr:Input name="username"/>
<wr:Input name="password"/>
<wr:Input name="parameter"/>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://examples.webratio.com/">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-32392973" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>[%= inputParams.username %]</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
[%= inputParams.password %]
</wsse:Password>
<wsse:Nonce>t2xCiUy6KLUs3FngzyYpgw==</wsse:Nonce>
<wsu:Created>2007-12-31T10:00:00.000Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<pj:getProject>
<projectCode>[%= inputParams.parameter %]</projectCode>
</pj:getProject>
</soapenv:Body>
</soapenv:Envelope>
The Web Service Provider
WebRatio 5.1 has a new feature that allows to add Web Service Provider to the Web Project. This feature helps to prepare the invocation of a Web Service. See Using a Web Service Provider for more information.