WebServices

WebServices for Tcl

A SOAP WEB Server client and server written in TCL

Both Client and Server side require tdom and either 8.6 (Version 3.x) or 8.4 + dict extension for Version 2.x.


Example of Web Services and the Google API

On August 8, 2006, Gerald Lester announced on comp.lang.tcl his web services library. This library, Web Services for Tcl [L1 ], provides commands to both easily create web services and to access web services from a client.

This article gives a briefto the client side of Gerald's library by presenting an example that accesses the Google SOAP Search API [L2 ] with just a couple dozen lines of code.

  Show hole article

Installing necessary software

Before you can run the examples in this article you will need to download and install some software and obtain a license key for the Google web service.

Unfortunately, the Tcl community does not yet have a definitive way to download and install packages so you'll have to perform a couple of manual steps. It is easy though; the matter boils down to downloading the software and copying it to a directory where your particular installation of Tcl will find it.

Downloading the Web Services library and dependencies

To access any web service using thepresented in this article you will need Gerald Lester's library. You can download it here: [L3 ]

Once downloaded, copy the folder to a location where tcl can find it. Start up a tcl shell and print theof the variable ::auto_path. Put the WebServices folder in one of the directories that is printed out.

You must also make sure you have all of the other dependencies installed on yourThese dependencies are listed on the same page where you find the web services library. If you are running a recent version of ActiveTcl [L4 ] you've likely already got all the dependencies so you'll only need to download and install the web services library.

One final note: the web services library and the example in this article make use of a new feature in tcl 8.5 named dict [L5 ]. Even though dict is a new feature in 8.5, a backport for 8.4 is available as a loadable extension here [L6 ] if you don't yet have an early release of tcl 8.5 installed on your machine.

Obtaining a Google API License

To gain access to the Google search API you must register with Google and get a license key. If you already have a gmail account it's just a matter of asking for the key. If you don't have an account you'll have to set one up, awhich takes just a couple of minutes. Start theby going to [L7 ]. Note that you do not have to download their developers kit, you simply need a license key to perform the search.

First steps

We're going to create a script named "googleapi.tcl". Since we are needing to use the web services library we must add a statement to load the library at startup. This first version of the script will look like this:

package require WS::Client
package require dict

proc main {} {
    puts "The library is properly installed"
}

main

(The main procedure isn't strictly necessary but I find it makes the code easier to write and maintain. For more on this, read the article Your Second Tcl Program [L8 ].)

If you save the above code in a file named googleapi.tcl and run it with the command tclsh googleapi.tcl you should see the output "The library is properly installed".

Fetching and Parsing the Web Service WSDL

Now that we know we can access the web services library, the next step is to make sure we can access and parse the WSDL. The WSDL for the Google SOAP search API is at [L9 ]. If you click the link you'll get back an XML document that describes the service in detail.

Before we can call a service at this address we must first fetch and parse this document with ::WS::GetAndParseWSDL. Modify the main procedure to look like this:

proc main {} {
    ::WS::Client::GetAndParseWsdl "http://api.google.com/GoogleSearch.wsdl"
    puts "WSDL successfully fetched and parsed"
}

If you again run your script, this time you should see "WSDL successfully fetched and parsed".

This step is necessary as it initializes the web services library to know about the operations and arguments supported by the given web service. This step is notto the google API — no matter what web service you want to access, it all begins with fetching and parsing the WSDL.

Making the Call

The web services library can be used to make both synchronous and asynchronous calls to the web service. The simplest case is to make a synchronous call that returns a dict. We do this by calling the function WS::Client::DoCall.

Assuming the call succeeds, we will get back a dict object that contains the data returned by the web service. A dict can also be treated as a set of nested lists, so you aren't yet up to speed on dicts you can use ordinary tcl list commands to pull the data apart.

In the case of the Google API, we must pass in a number of arguments as defined by the WSDL (and on the human readable description at 2). The argument list itself is a dict, but can also be thought of as a list of keys and To print out the raw data, our main procedure now looks like this:

proc main {} {
    ::WS::Client::GetAndParseWsdl "http://api.google.com/GoogleSearch.wsdl"

    dict set args key "<your google license key here>"
    dict set args q {site:tclscripting.com font}
    dict set args start 0 
    dict set args maxResults 10
    dict set args filter true 
    dict set args restrict {} 
    dict set args safeSearch false
    dict set args lr {} 
    dict set args ie latin1 
    dict set args oe latin1

    set result [::WS::Client::DoCall GoogleSearchService doGoogleSearch $args]
    puts $result
}

You should see output that looks something like this:

return {searchComments {} resultElements {item {{relatedInformationPresent true summary {} title { to named <b>fonts</b>} URL http://www.tclscripting.com/articles/jun06/article1.html snippet {This article briefly describes how and why you should use named <b>fonts</b>. <b>...</b> <br> The advantage to using named <b>fonts</b> is that when the <b>font</b> is<b>...</b>} cachedSize 15k hostName {} directoryCategory {specialEncoding {} fullViewableName {}} directoryTitle {}} {relatedInformationPresent true summary {} title {Your second Tcl/Tk application} URL http://www.tclscripting.com/articles/sep06/article1.html snippet {package man page, https://www.tcl-lang.org/man/tcl8.4/TkCmd/<b>font</b>.htm ; sqlite <br> http://www.sqlite.org ; tcllib http://tcllib.sourceforge.net <b>...</b>} cachedSize 14k hostName {} directoryCategory {specialEncoding {} fullViewableName {}} directoryTitle {}}}} searchQuery {site:tclscripting.com font} estimateIsExact true searchTime 0.014507 startIndex 1 searchTips {} documentFiltering false estimatedTotalResultsCount 2 endIndex 2 directoryCategories {}}

Making sense of the results

Unlike dealing with block of raw XML, dealing with the output returned by ::WS::Client::DoCall is quite simple. The result is a dict, which is to say it is a nested list of keys anddicts are a new feature of Tcl 8.5, with a backport available as a loadable extension for tcl 8.4. While the data can be manipulated with traditional list commands, using dict commands makes parsing the output quite simple.

As a simple example, the following code prints out the title and URL of each page returned by the query:

foreach item [dict get $result return resultElements item] {
    puts [dict get $item title]
    puts [dict get $item URL]
    puts ""
}

Putting it all together

As you can see, using the Web Services for Tcl library along with the new dict feature of tcl 8.5, accessing web services is remarkably simple. In our example we are able to formulate a request, make the request, and parse the results, all with just a couple dozen lines of code.

Of course, this just scratches the surface of what we can do. The web services library provides even more features such as the ability to make asynchronous calls, saving and loading pre-parsed WSDL documents, and being able to send and receive additional headers in the SOAP envelope.

The complete script looks like the following:

package require WS::Client
package require dict

proc main {} {
    ::WS::Client::GetAndParseWsdl http://api.google.com/GoogleSearch.wsdl

    dict set args key "<your google license key here>"
    dict set args q {site:tclscripting.com font}
    dict set args start 0 
    dict set args maxResults 10
    dict set args filter true 
    dict set args restrict {} 
    dict set args safeSearch false
    dict set args lr {} 
    dict set args ie latin1 
    dict set args oe latin1

    set result [::WS::Client::DoCall GoogleSearchService doGoogleSearch $args]

    foreach item [dict get $result return resultElements item] {
        puts [dict get $item title]
        puts [dict get $item URL]
        puts ""
    }
}

main

I'm not sure it can be any easier to access a web service no matter what language you use. Gerald Lester has given the Tcl community a real gem.

© 2006 Bryan Oakley


TLS

TCLWS 3.0.0 tries to improve the support of HTTPS / TLS. TCLTLS and twapi is supported on client and server.

If you want to use the embedded server and a self-signed certificate, you may look to the remarks on this page: Embedded TCL Web Server.

There are several open points:

  • Embedded server: Switch server verification off on TWAPI (as an option).
  • CLient and Server: TCLTLS packages may need a bunch of options which may currently not be set.

Questions

Has anyone worked on UDDI support for software written using WebServices?

See also


Web Service

Consuming web services