| 1 |
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
| 2 |
<page name="cduce_ws">
|
| 3 |
|
| 4 |
<title>CDuce_WS</title>
|
| 5 |
<left>
|
| 6 |
<p>
|
| 7 |
This page is an introduction to CDuce_WS.
|
| 8 |
</p>
|
| 9 |
<boxes-toc/>
|
| 10 |
<p>See also:</p>
|
| 11 |
<local-links href="index,memento,manual,tutorial"/>
|
| 12 |
</left>
|
| 13 |
|
| 14 |
<box title="Introduction" link="intro">
|
| 15 |
|
| 16 |
<p>
|
| 17 |
CDuce_WS is library for Web Services creation. It can be used alone
|
| 18 |
for the creation of clients programs, and
|
| 19 |
with <a href="http://ocsigen.org/occduce">OcCDuce</a> for servers.
|
| 20 |
</p>
|
| 21 |
<p> Basically, CDuce_WS is a CDuce representation of the SOAP protocol
|
| 22 |
structures (SOAP Envelope, SOAP Encoding, etc.) with some helper
|
| 23 |
functions to ease the programmation of Web Services.
|
| 24 |
Additionally, a WSDL structure is also provided, as well as some
|
| 25 |
functions (adapted from
|
| 26 |
<a href="http://forge.ocamlcore.org/projects/ocsoap/">OCSoap</a>) to
|
| 27 |
extract useful information from a WSDL file.
|
| 28 |
</p>
|
| 29 |
</box>
|
| 30 |
<box title="First example" link="first">
|
| 31 |
<p>
|
| 32 |
This example corresponds to the example in the directory: examples/echo/.
|
| 33 |
<br/>
|
| 34 |
It is a very simple service that receive an integer from a client and
|
| 35 |
send it back.
|
| 36 |
<br/>
|
| 37 |
The first file, <b>common.cd</b>, contains all the declarations used by
|
| 38 |
the client and the server, and is included by all other files.
|
| 39 |
The type <b>Msg</b> corresponds to the information that a client send
|
| 40 |
to the server, while the type <b>Answer</b> embeds the response from
|
| 41 |
the server to the client.
|
| 42 |
</p>
|
| 43 |
<sample><![CDATA[namespace on;;
|
| 44 |
using SoapEnv = "soapenv";;
|
| 45 |
namespace ns = "urn:echo"
|
| 46 |
|
| 47 |
type Msg = <ns:echoInteger>[
|
| 48 |
<inputInteger>Latin1
|
| 49 |
];;
|
| 50 |
|
| 51 |
type Answer = <ns:echoIntegerResponse> [
|
| 52 |
<return>Latin1
|
| 53 |
];;
|
| 54 |
]]></sample>
|
| 55 |
|
| 56 |
<p>The next file, <b>ws_echo.cd</b>, contains the code necessary
|
| 57 |
to register a web service in Ocsigen, via OcCduce.
|
| 58 |
<br/>
|
| 59 |
The call to <b>Lib.register_webservice</b> registers 2
|
| 60 |
services in Ocsigen:
|
| 61 |
</p>
|
| 62 |
<ul>
|
| 63 |
<li> <code>wsEcho</code>, which is called when a client requests the URL with
|
| 64 |
the POST method. The first argument corresponds to the POST
|
| 65 |
parameters, the second argument to the GET parameters and the third
|
| 66 |
one is the content of the request. POST and GET parameters are
|
| 67 |
empty in case of a web service. The content of the request is the
|
| 68 |
SOAP message as a string (actually a Latin1 string).</li>
|
| 69 |
<li> <code>wsError</code>, which is called if the client uses the
|
| 70 |
GET method (hopefully, it should not happen). </li>
|
| 71 |
</ul>
|
| 72 |
<p><b>NOTE1:</b> it is not possible to load more than once the same
|
| 73 |
CDuce program in OcCDuce. Therefore, you should never give the same
|
| 74 |
name to the source files of different services if you plan to load
|
| 75 |
them simultaneously.
|
| 76 |
</p>
|
| 77 |
<p>
|
| 78 |
<b>NOTE2:</b>Sometimes, the namespaces used by the client and the
|
| 79 |
server do not match. This problem can be avoided by using 3
|
| 80 |
functions:<code>Cduce_ws.load_xml_subst</code>,
|
| 81 |
<code>Cduce_ws.print_xml_subst</code>,
|
| 82 |
and <code>Occduce_lib.set_subst_uri</code>.
|
| 83 |
Both load_xml_subst and print_xml_subst are equivalent to load_xml and
|
| 84 |
print_xml with an additional parameter, a list of pairs of URIs. For
|
| 85 |
each pair of URIs, the first one is the original (i.e. used in the
|
| 86 |
in the other parameter), and the second URI is the new URI. Every
|
| 87 |
original URI will be substituted by the new one in the returned
|
| 88 |
value.
|
| 89 |
<br/>
|
| 90 |
<code>set_subst_uri</code> also takes a list of pairs of URIs as a
|
| 91 |
parameter, and it must be used <b>before</b> returning the
|
| 92 |
XML value in the server. The namespaces of the XML value returned
|
| 93 |
will be converted before it is sent to the client.
|
| 94 |
</p>
|
| 95 |
|
| 96 |
<sample><![CDATA[include "../common.cd"
|
| 97 |
using Echo = "echo";;
|
| 98 |
using Lib = "occduce_lib";;
|
| 99 |
|
| 100 |
let wsError (_ : []) : AnyXml =
|
| 101 |
SoapEnv.std_soap_fault;;
|
| 102 |
|
| 103 |
let wsEcho (_ : []) (_ : []) (content : Latin1) : AnyXml =
|
| 104 |
Occduce.debug_string "wsEcho\n";
|
| 105 |
try
|
| 106 |
(let a = Echo.echo content in
|
| 107 |
Occduce.set_subst_uri
|
| 108 |
[("http://schemas.xmlsoap.org/soap/envelope",
|
| 109 |
"http://schemas.xmlsoap.org/soap/envelope/")];
|
| 110 |
a)
|
| 111 |
with err & Latin1 ->
|
| 112 |
Occduce.debug_string [ 'Cduce exception: ' !err '\n'];
|
| 113 |
exit 2;;
|
| 114 |
|
| 115 |
let ws_echo =
|
| 116 |
Lib.register_webservice
|
| 117 |
{ path = ["ws_echo"]; serviceName = "wsEcho" }
|
| 118 |
wsEcho wsError
|
| 119 |
]]></sample>
|
| 120 |
<p>
|
| 121 |
The next file, <b>echo.cd</b>, contains the processing of the SOAP
|
| 122 |
message and the generation of the response message.
|
| 123 |
<br/>
|
| 124 |
<code>load_xml_subst</code> converts the string containing the SOAP
|
| 125 |
message in a SOAP XML structure after the substitution of the URIs
|
| 126 |
(obviously, using namespaces substitution in the server and client
|
| 127 |
code is not useful).
|
| 128 |
<br/>
|
| 129 |
The body of the SOAP structure, a list of AnyXml, is extracted with the
|
| 130 |
function <code>SoapEnv.extract_message</code>, while the
|
| 131 |
function <code>SoapEnv.hd</code> returns the first XML structure in
|
| 132 |
the list.
|
| 133 |
<br/>
|
| 134 |
After the processing of the message and the creation of the response
|
| 135 |
message, <code>SoapEnv.to_soap</code> embeds it in a SOAP envelope.
|
| 136 |
</p>
|
| 137 |
<sample><![CDATA[include "../common.cd"
|
| 138 |
|
| 139 |
let echo (s : Latin1) : SoapEnv.Envelope =
|
| 140 |
let xml = Cduce_ws.load_xml_subst [ 'string:' !s]
|
| 141 |
[("http://schemas.xmlsoap.org/soap/envelope",
|
| 142 |
"http://schemas.xmlsoap.org/soap/envelope/")]
|
| 143 |
in
|
| 144 |
let res = SoapEnv.hd (SoapEnv.extract_message xml) in
|
| 145 |
let tmp :? Msg = res in
|
| 146 |
let number = (match tmp with <ns:echoInteger>[<inputInteger>n] -> n)
|
| 147 |
in
|
| 148 |
let msg =
|
| 149 |
<ns:echoIntegerResponse>[
|
| 150 |
<return> number
|
| 151 |
] in
|
| 152 |
SoapEnv.to_soap msg;;
|
| 153 |
]]></sample>
|
| 154 |
<p>
|
| 155 |
The last file, <b>client.cd</b>, executes the following steps:
|
| 156 |
</p>
|
| 157 |
<ul>
|
| 158 |
<li>it creates a message of type Msg. <b>NOTE:</b>Since we need to
|
| 159 |
use load_xml or load_xml_subst to convert the string in XML, it is
|
| 160 |
not possible to use primitive types such as integer in the types
|
| 161 |
transmitted between the client and the server. We can only use
|
| 162 |
Latin1 strings</li>
|
| 163 |
<li>the message is embedded in a SOAP envelope
|
| 164 |
using <code>SoapEnv.to_soap</code>, and converted as a string by
|
| 165 |
<code>print_xml_subst</code>.</li>
|
| 166 |
<li>the string message is sent to the server
|
| 167 |
with <code>Cduce_ws.send</code>, where the parameters are: the
|
| 168 |
message string, the host address, the soap action, and the content
|
| 169 |
type.
|
| 170 |
<br/> The returned value of <code>send</code> is a Latin1 string
|
| 171 |
with the response message in SOAP.
|
| 172 |
</li>
|
| 173 |
<li>the response message is converted back in XML by <code>load_xml_subst</code>.</li>
|
| 174 |
<li>the body part of the SOAP response is extracted
|
| 175 |
using <code>SoapEnv.extract_message</code>, and printed.</li>
|
| 176 |
</ul>
|
| 177 |
<sample><![CDATA[include "../common.cd"
|
| 178 |
let msg : Msg =
|
| 179 |
<ns:echoInteger>[
|
| 180 |
<inputInteger>['1234567890']
|
| 181 |
];;
|
| 182 |
|
| 183 |
let _ =
|
| 184 |
let string_msg = Cduce_ws.print_xml_subst (SoapEnv.to_soap msg)
|
| 185 |
[("http://schemas.xmlsoap.org/soap/envelope/",
|
| 186 |
"http://schemas.xmlsoap.org/soap/envelope")]
|
| 187 |
in
|
| 188 |
let answer_string = Cduce_ws.send string_msg
|
| 189 |
"http://localhost/ws/ws_echo" "" "text/xml; charset=utf-8" in
|
| 190 |
print [ 'CDuce: ' !answer_string '\n'];
|
| 191 |
let xml = Cduce_ws.load_xml_subst [ 'string:' !answer_string]
|
| 192 |
[("http://schemas.xmlsoap.org/soap/envelope",
|
| 193 |
"http://schemas.xmlsoap.org/soap/envelope/")]
|
| 194 |
in
|
| 195 |
print (string_of (SoapEnv.extract_message xml));;
|
| 196 |
]]></sample>
|
| 197 |
</box>
|
| 198 |
<box title="A more advanced example" link="calc">
|
| 199 |
<p>
|
| 200 |
This example corresponds to the example in the directory: examples/calc/.
|
| 201 |
<br/>
|
| 202 |
It is a simple calculator over integer values that receive two values
|
| 203 |
with an operator from a client and return the result.
|
| 204 |
<br/>
|
| 205 |
The first file, <b>common.cd</b>, contains all the declarations used by
|
| 206 |
the client and the server, and is included by all other files.
|
| 207 |
The type <b>Operation</b> corresponds to all possible operations that
|
| 208 |
a client can send
|
| 209 |
to the server, while the type <b>Response</b> embeds the result sent by
|
| 210 |
the server to the client.
|
| 211 |
</p>
|
| 212 |
|
| 213 |
<sample><![CDATA[namespace on;;
|
| 214 |
namespace ns = "urn:calc"
|
| 215 |
using SoapEnv = "soapenv";;
|
| 216 |
|
| 217 |
type Params = [ <a>Latin1 <b>Latin1 ];;
|
| 218 |
type AddIn = <ns:add>Params;;
|
| 219 |
type SubIn = <ns:sub>Params;;
|
| 220 |
type MulIn = <ns:mul>Params;;
|
| 221 |
type DivIn = <ns:div>Params;;
|
| 222 |
type Result = <result>Latin1;;
|
| 223 |
type AddOut = <ns:addResponse>[Result];;
|
| 224 |
type SubOut = <ns:subResponse>[Result];;
|
| 225 |
type MulOut = <ns:mulResponse>[Result];;
|
| 226 |
type DivOut = <ns:divResponse>[Result];;
|
| 227 |
type Operation = AddIn | SubIn | MulIn | DivIn;;
|
| 228 |
type Response = AddOut | SubOut | MulOut | DivOut;;
|
| 229 |
]]></sample>
|
| 230 |
|
| 231 |
<p>The next file, <b>ws_calc.cd</b>, contains the code necessary
|
| 232 |
to register a web service in Ocsigen, via OcCduce.
|
| 233 |
<br/>
|
| 234 |
It is quite similar to the code from the previous example.
|
| 235 |
</p>
|
| 236 |
|
| 237 |
<sample><![CDATA[include "../common.cd"
|
| 238 |
using Calc = "calc";;
|
| 239 |
using Lib = "occduce_lib";;
|
| 240 |
|
| 241 |
let wsError (_ : []) : AnyXml =
|
| 242 |
SoapEnv.std_soap_fault;;
|
| 243 |
|
| 244 |
let wsCalc (_ : []) (_ : []) (content : Latin1) : AnyXml =
|
| 245 |
Occduce.debug_string "wsCalc\n";
|
| 246 |
try (Calc.calc content)
|
| 247 |
with err & Latin1 ->
|
| 248 |
Occduce.debug_string [ 'Cduce exception: ' !err '\n'];
|
| 249 |
exit 2;;
|
| 250 |
|
| 251 |
let ws_calc =
|
| 252 |
Lib.register_webservice
|
| 253 |
{ path = ["ws_calc"]; serviceName = "wsCalc" }
|
| 254 |
wsCalc wsError
|
| 255 |
]]></sample>
|
| 256 |
|
| 257 |
<p>
|
| 258 |
The next file, <b>calc.cd</b>, contains the processing of the SOAP
|
| 259 |
message and the generation of the response message.
|
| 260 |
<br/>
|
| 261 |
<code>load_xml</code> converts the string containing the SOAP
|
| 262 |
message in a SOAP XML structure which is passed
|
| 263 |
to <code>SoapEnv.extract_message</code> and <code>SoapEnv.hd</code> to
|
| 264 |
extract the content of the body of the SOAP structure.
|
| 265 |
<br/>
|
| 266 |
The function <code>compute</code> processes the message and returns a
|
| 267 |
result in a response message, which is embedded in a SOAP envelope by <code>SoapEnv.to_soap</code>.
|
| 268 |
</p>
|
| 269 |
|
| 270 |
<sample><![CDATA[include "../common.cd"
|
| 271 |
using SoapEnv = "soapenv";;
|
| 272 |
|
| 273 |
let compute (op : Operation) : Response =
|
| 274 |
match op with
|
| 275 |
<ns:add>[<a>a <b>b] ->
|
| 276 |
<ns:addResponse>[<result>(string_of ((int_of a) + (int_of b)))]
|
| 277 |
| <ns:sub>[<a>a <b>b] ->
|
| 278 |
<ns:subResponse>[<result>(string_of ((int_of a) - (int_of b)))]
|
| 279 |
| <ns:mul>[<a>a <b>b] ->
|
| 280 |
<ns:mulResponse>[<result>(string_of ((int_of a) * (int_of b)))]
|
| 281 |
| <ns:div>[<a>a <b>b] ->
|
| 282 |
<ns:divResponse>[<result>(string_of ((int_of a) div (int_of b)))];;
|
| 283 |
|
| 284 |
let calc (s : Latin1) : SoapEnv.Envelope =
|
| 285 |
let xml = load_xml [ 'string:' !s] in
|
| 286 |
let res = SoapEnv.hd (SoapEnv.extract_message xml) in
|
| 287 |
let op :? Operation = res in
|
| 288 |
let answer = compute op in
|
| 289 |
SoapEnv.to_soap answer;;
|
| 290 |
]]></sample>
|
| 291 |
|
| 292 |
<p>
|
| 293 |
The last file, <b>client.cd</b>, executes the following steps:
|
| 294 |
</p>
|
| 295 |
<ul>
|
| 296 |
<li>it creates a message of type Operation. </li>
|
| 297 |
<li>the message is embedded in a SOAP envelope
|
| 298 |
using <code>SoapEnv.to_soap</code></li>
|
| 299 |
<li>it is then converted as a string by
|
| 300 |
<code>print_xml</code> and sent to the server
|
| 301 |
with <code>Cduce_ws.send</code>, where the parameters are: the
|
| 302 |
message string, the host address, the soap action, and the content
|
| 303 |
type.
|
| 304 |
<br/> The returned value of <code>send</code> is a Latin1 string
|
| 305 |
with the response message in SOAP.
|
| 306 |
</li>
|
| 307 |
<li>the response message is converted back in XML by <code>load_xml</code>.</li>
|
| 308 |
<li>the body part of the SOAP response is extracted
|
| 309 |
using <code>SoapEnv.extract_message</code>, and printed.</li>
|
| 310 |
</ul>
|
| 311 |
|
| 312 |
<sample><![CDATA[include "../common.cd"
|
| 313 |
using SoapEnv = "soapenv";;
|
| 314 |
|
| 315 |
let msg :? Operation = <ns:add>[ <a>"24" <b>"18" ];;
|
| 316 |
|
| 317 |
let _ =
|
| 318 |
let msg_soap = SoapEnv.to_soap msg in
|
| 319 |
let answer_string = Cduce_ws.send (print_xml msg_soap)
|
| 320 |
"http://localhost/ws/ws_calc" "" "text/xml; charset=utf-8" in
|
| 321 |
print [ 'CDuce: ' !answer_string '\n'];
|
| 322 |
let xml = load_xml [ 'string:' !answer_string ] in
|
| 323 |
let soap_answer :? SoapEnv.Envelope = xml in
|
| 324 |
print (string_of (SoapEnv.extract_message xml));;
|
| 325 |
]]></sample>
|
| 326 |
|
| 327 |
</box>
|
| 328 |
|
| 329 |
</page>
|
| 330 |
|
| 331 |
|