Forum OpenACS Development: Re: Tcl Web Services Toolkit: TWiST

Posted by Tom Jackson on
The client side has been somewhat sidetracked by the need to get an integration method that made the server easier to use. This took calendar time due to scheduling. However, TWiST didn't require any changes to tWSDL, which indicates that the tWSDL API is in good shape. In fact TWiST is a single example of how to apply tWSDL for different environments.

TWiST handles a simple general situation: interfacing with a single Tcl API (proc). A Tcl proc, in general, takes a list of values and returns a single value (which might be a list, who knows). The problem is that in Tcl there is no way to tell what types should be passed in or even less what is returned. An additional problem is that the passed in or returned value might be a list or the name of an array. The TWiST API provides a simple wrapper to handle these different situations.

Another important point is that helpful tools like ad_proc make simple introspection of an existing Tcl proc impossible. Handling switches is relatively complicated, and there are several version of ad_proc available. Same problem arises with the use of args, or for API which return complex data such as db_multirow.

Still another point is that an external web service should probably not expose every possible use of an internal API. Simple introspection in any language can never overcome this problem, and the developer will very quickly find that they are stuck hand coding a wrapper to handle the situation.

So the development cycle with TWiST is aimed at handling the typical situation: decide what to expose. Figure out what inputs are required. Write a script to create the inputs for the internal API. At some point these input will be composed of simpleTypes, and to use your internal API you must know how to transform these into the correct form. The next step is to call your internal API. Then these are transformed into a return value which at some level are represented as simpleTypes. The above script is the body of <ws>proc. This development cycle is identical to a tcl page in OpenACS prior to invoking the template code. The main difference is that instead of ad_page_contract, tWSDL handles, validates and transforms the input. Instead of ad_return_template, tWSDL transforms the result into a SOAP Response. TWiST is a configuration of the entire process.

Now: what about complexTypes? If you look at the testItOperation, notice that it returns a complexType {A B C}. A return type configuration is similar to the input type configuration, with the exception that the return types cannot specify default values. However this is only one level of complexType. I'm working on adding deeper structure to types, it isn't difficult, but the convenience proc which creates a sequence only handles a sequence of elements which contain simpleType content. I have verified that the same validation procedures work with complexContent, but I've just finished with a hand written example and it isn't integrated into tWSDL yet. Eventually there will probably be a TWiST API: <ws>type to expose this, or I might change the internal storage so that the API can look up the type and figure out what to do.

Using tWSDL allows more complete control over defining types, but I haven't specifically tested the idea of creating a type in tWSDL just to use it in TWiST. However, note that TWiST is already doing this. Types are specified by similar syntax as used in ad_proc: myVar:typeName. The difference is that TWiST and tWSDL used namespaces for types, the default being XML-Schema types, which has a prefix of xsd. The prefix is used in the schema database as a Tcl namespace name. Each prefix has only one namespace uri. Externally, you can use a different prefix. Internally they are mapped to specific prefixes. So, when you create a new web service with TWiST, the tail of the Tcl namespace is used as the prefix internally. The namespace uri becomes 'urn:tcl:yournamespace' by default. This can be modified. So if you use tWSDL to create a type, you would create it in some xml namespace with associated prefix. To use it, you use the prefix: {a:mytypes::specialType b:somexsdType}. It is important to always derive your types from xsd types since tWSDL always imports all types into the WSDL. That way, clients will be able to validate your documents.