Updated 2016-03-17 09:53:04 by ALX

GWL 10/18/2006 See WebServices for Tcl [1] (previously [2]) for a client and server (currently only runs in TclHttpd), now at version 1.2.0 ..

Client side supports parsing of WSDLs.

Server side supports automatic generation of WSDLs and Infomation pages.

Both Client and Server side require tdom and either 8.5 or the dict extension.

The download provides these packages: WS::Client, WS::Server, and WS::Utils .

See http://www.tclscripting.com/articles/nov06/article1.html for a description of using the above package.

NEM 2010-10-20: This article is currently blocked by my employer as a "parked domain". Has the tclscripting.com domain lapsed?

AMG: It looks like it to me.

lm09/05/2011 : you can find it here: http://web.archive.org/web/20080706181654/http://www.tclscripting.com/

AMG: By the way, my employer blocks archive.org. Also Google Translation and Google Cache. But thanks anyway. Lucky for me I'm at home now. ;^) Anyway, here's a copy of the page, pasted inline:

Web Services and the Google API  edit

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

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

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 the techniques presented in this article you will need Gerald Lester's library. You can download it here: [5]

Once downloaded, copy the folder to a location where tcl can find it. Start up a tcl shell and print the value of 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 your system. These dependencies are listed on the same page where you find the web services library. If you are running a recent version of ActiveTcl [6] 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 [7]. Even though dict is a new feature in 8.5, a backport for 8.4 is available as a loadable extension here [8] 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, a process which takes just a couple of minutes. Start the process by going to [9]. 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 [10].)

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 [11]. 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 not unique to 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 values.

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 {Introduction 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 changed, <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, http://www.tcl.tk/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 and values. dicts 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

See also


Web Service

Consuming web services

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