![]() |
|
|
|
Simple
Object and Data Access (SODA) Remote
|
SODA-RPC (or SODA for short) stands for Simple Object and Data Access. It's a protocol that provides an easy way for web applications to communicate with a web server. The transport uses XML to send and receive data to and from the server. No XML parser is required since SODA-RPC uses a very simple layout to convert data variables into an XML document and back.
Click
here to see a live Calculator Application using SODA-RPC. An ASP compatible
web server is required.
XML is a widely used data format for exchanging data on the web, but it requires the overhead of an XML parser and data often times will have to be converted to the desired data type for use with the application.
A SOAP-RPC Web Service provides another way for programmers to send and receive information to and from a web server, but it too requires the web server and browser to have special software installed to in order to communicate.
SODA-RPC might not be as powerful as SOAP, but it’s powerful enough to get the job done right
Key Features:
It's very simple! All you have to do is download DynAPI 2.9 and include the following inside the <head> tag of your html document:
<script language="JavaScript" src="../src/dynapi.js"></script> <script language="Javascript"> dynapi.library.setPath('../src/'); dynapi.library.include('dynapi.api'); dynapi.library.include('dynapi.library'); dynapi.library.include('dynapi.util.IOElement'); dynapi.library.include('dynapi.util.IOElementSoda'); </script>
The first line must point to the location of your dynapi.js file:
<script language="JavaScript" src="../src/dynapi.js"></script>
Secondly you want to make sure you set the path to the dynapi library files (it's usually the same path as that of the dynapi.js file):
dynapi.library.setPath('../src/');
Now that we've included the necessary library files into our html document, it's
now time to explore create a connection to the server.
The first thing to do is to create a new IOElement object.
var io = new IOElement(1); // create only one asynchronous thread
Next we'll connect to the service using the createWebService method. The createWebService has the following arguments:
createWebService(name,url,fn,uid,pwd,method) name - client-side name used to identify the service url - URL path to the web sercvice fn - Callback function useSync - Used to activate Synchronous transfers. uid - User ID pwd - User Password method - GET or POST method during calls. POST is used by default
The name argument makes it possible for you to
connect to more than one service using one IOElement object
example:
// io.createWebService(bksrv,"bkman.asp",initWS,false); // io.createWebService(hrms,"hrms.asp",initWS,false); // create a synchronous connection io.createWebService(calc,"calc.asp",initWS,true);
function initWS(calc,s,errorText){ if(s!=true) { alert('An Error occured while creating web service: '+errorText); return; } // access the calc service calc.call("multiply", [5,6],fn); }
Once we've established a synchronous connection with the service we can now import methods located on the server by using the importWebMethods() function. This function will only work with synchronous calls. You can NOT import web methods when using asynchronous calls!
var rt=io.calc.importWebMethods(); if (!rt) alert('Unable to import web method');
So far we've manage to include the necessary libraries, create a connection and import web methods exposed by the service. Our next step is to place both asynchronous and synchronous calls to the service.
To place a asynchronous call to the server we'll use the call method.
var id = io.calc.call('multiply', [4,5],fn); // do some work here function fn(e,s){ var o = e.getSource(); var r = o.getResponse(); // get Response object var f=document.forms["calculator"]; if(!r.error) f.txtdisplay.value = r.value; else { var er=r.error.text+'\n\nTo retry the request click the OK button'; if (confirm(er)) o.retry(); else o.cancel(); } }
The above will call the multiply() method on the server and pass it the arguments 4 and 5. The fn argument is used as the callback function that's called when the server has issued a response. The value returned from the call() function can be used later to cancel the call or to perform a retry operation if the call had failed.
To place a synchronous call to the service we can
do it using one of two methods. The first is to use the call() method with the
callback function set to false. The second is to use the imported web methods:
1) Using the call function.
var response = io.calc.call('subtract',[9,19],false); // note: no callback function is used. if (response.error) alert(response.error.text); else { alert(response.value); }
2) Using imported web methods
var response = io.calc.subtract(4,5);
Note that an object is returned after a synchronous call is made. This object is called the Response Object. It contains the returned value and an error object if there was an error during the call.
The call() function can also be used to place
multiple calls to the server in either async/sync modes.
Let's say we want to perform the following
calculation via our web service:
23+(((5*7)-6)/2) which is equal to 37.5
With conventional tools you would have to make several calls to the server or create a function on the server that can perform the above calculation. But what it you're not able to create the function on the server? Then you'd just have to stick with with what you have. SODA-RPC solves the above problem by allowing you to not only make multiple calls but to also pass arguments from one method to the next in a single call to the server!
Here's how it's done using a simple object:
var dta={ multiply:[5,7], subtract:['@RESULT#0',6], divide:['@RESULT#1',2], add:[23,'@RESULT#2'] } var response = io.calc.call(dta,null,false); if (response.error) alert(response.error.text); else { alert(response.value[3]); // displays 37.5 }
Or we could be it this way using arrays:
var mns='multiply,subtract,divide,add'; var args=[ [5,7], ['@RESULT#0',6], ['@RESULT#1',2], [23,'@RESULT#2'] ]; var response = io.calc.call(mns,args,false); if (response.error) alert(response.error.text); else { alert(response.value[3]); }
Using the later makes it possible for you to use a method more than once. For example:
((23*4)+12)*3 can be represented as:
var mns='multiply,add,multiply'; var args=[ [23,4], ['@RESULT#0',12], ['@RESULT#1',3] ]; var response = io.calc.call(mns,args,false) if (response.error) alert(response.error.text); else { alert(response.value[2]); }
The value return in the response object is an array
containing the results of all the methods called on the server.
Note: Using Synchronous transfers will block the executing script will it waits
for a response from the server. In my opinion it's best to use asynchronous
transfers as it allows for more control.
The soda protocol has 8 types of data. All values have one of these types:
- Undefined/Null
- The Undefined or Null type has one value only, null.
- Boolean
- The Boolean type represents the two logical values, true and false.
- String
- Strings are delineated by single or double quotation marks and can contain zero or more characters. An empty string has zero characters and length.
- Integer
- The integer type represents positive or negative numbers without a decimal point.
- Float
- The float type represents positive or negative numbers with a decimal point. A floating-point literal must have at least one digit and either a decimal point.
- Date
- The Date type stores a valid date entry in the format mm/dd/yyy hh:nn:ss
- Array
- An Array is a series of data elements of mixed data types.
- Object
- The Object type is represents an associative (hash) array used for storing name and value pairs.
Data Types | JavaScript | VBScript | Perl |
Date | Date | Date | scalar ($) |
String | String | String | scalar ($) |
Integer | Integer | Long Integer | scalar ($) |
Float | Float | Double | scalar ($) |
Boolean | Boolean | Boolean | scalar ($) |
Array | Array [] | Array | Array [] |
Associative Array | Object {} | Dictionary Object | Hashes % |
The server or client libraries can be easily ported to other languages (such as php, python, java, tcl)
You first need to include the following set of files:
Where * is used to represent the language and extension of the file. For example * would represent jscript.asp which would result in ioelmsrv.jscript.asp and ioelmsrv.soda.jscript.asp
- DynAPI 3.0 Library files supports SODA-RPC
Note: If you'd like to create a library file for another scripting language you can use the soda-tester example page to test the functions of the library.
The first thing you'll be needing is the IOElement Server and SODA-RPC library files for the server-side script that you're using. There are currently three server-side scripts avaiable:
The above libraries can be easily ported to other languages.
Server-Side Methods:
wsAddDescription(name,text) - Add a description to a method or its parameters. When online help is enabled users will be able to see the description of the methods or parameters.
wsAddDescription("aboutMe","Company Information - Name, Email, etc") wsAddDescription("add","Add two numeric values and returns the result") wsAddDescription("add:a","Numeric value") wsAddDescription("add:b","Numeric value")
wsAddMethod(name,params,rtype) - Used for adding a methods to the service. Methods added will be made public.
wsAddMethod('search',['fname:string','age:integer:0'],'array'); wsAddMethod('clearcache',null,'boolean'); // method does not accept arguments
The params argument can be a string or and array of string parameters. Each parameter is defined as:
Name of argument:Data Type:Default Value
wsAddErrorCode(code,text) - Used for adding error codes to the service. These codes can be triggered by using the wsRaiseError() method
wsAddErrorCode("D2","Test Error"); // some code here wsRaiseError("D2"); // later raise error D2
wsAddVariable(name,value) - Used for adding JavaScript variables which will be returned to the client current client
wsCaptureEvent(evnt,fn) - Used for capturing Dispatch and Login events triggered by the service.
wsCaptureEvent("login",login); wsCaptureEvent("logout",logout); wsCaptureEvent("dispatch",dispatch); wsDispatch(); function login(uid, pwd, sid) { if (uid=="myname" && pwd=="mypassword") { Session.Contents(sid)="ok"; return true; //returns true if successful } }; function logout(sid) { Session.Contents(sid)=""; return true; //returns true if successful }; function dispatch() { var sid; sid=wsGetSessionId(); if (Session.Contents(sid)!="ok"); return false; //returns false to prevent dispatch };
wsDispatch() - Dispatches methods and variables if IOResponse is set to html (default-asynchronous) otherwise only methods are dispatched
wsDispatchVariables() - Dispatches JavaScript variables to client. Should only be used with Asynchronous calls. A SODA-RPC library can be used on the server-side to dispatch variables to the client when a call is made via IOElement's get(), post() or upload() methods.
wsAddVariable('count',2); wsAddVariable('name','Mary Jane'); wsDispatchVariables(); // returns JavaScript variables to client;
wsEnableOnlineHelp(b) - Used to enable or disable online help/debug. When set the false users will only be able to see the main splash screen.
wsEnableOnlineHelp(true)
wsGetRequest(name) - Returns form data submitted by client
var fname = wsGetRequest("firstname"); // client submitted "firstname"
wsGetRequestMethod() - Returns the method (GET, POST or UPLOAD) used to make the call
wsGetSessionId() - Returns the current caller's session id
wsIsHelpMode() - Returns true if in helpmode or false if not in help mode.
wsRaiseError(ecode,etext) - Returns an error to the client. This method can also be used to help debug server-side code:
function setDate(dt){ if(!dt) wsRaiseError(null,'You've entered:'+dt); else { // code to set date } }
wsSetComment(strComment) - Sets a comment or description for the service
wsSetName(strName) - Sets a name for the service
The SODA-RPC protocol makes it possible for any web server to act as a web service because it uses either GET or POST to send data to the server. There are two main variables used when submiting data, they are as follows:
IORepsonse - XML or HTML (default) - Sets the returned data format from the server
IOEnvelope - SODA-RPC XML document
example:
http://localhost/myserver.asp?IOResponse=XML&IOEnvelope=<soda.env> <sid>12232-33334-23243354-2332</sid> <method>Test</method> <body> <so.da></so.da> </body> </soda.env>
The XML/HTML formats make it possible for a SODA-RPC client to exist within a browser or within a desktop application
Let’s
say we have a web service app call Book Manager that was written in JavaScript and DHTML
on the client-side and VBScript on the server-side.
First I’m going to have to create a way for me to
send and receive data to and from the server. Next I need a way to send data in
the background.
This is how SODA-RPC makes it very easy to communicate with server-side apps:
IOElement SODA-RPC functions:
Constructor IOElement(hidden, useXFrames)
hidden – total number or threads or ports; useXFrames – use eXternal Frames for post request in NS4
createWebService(name, url, fn, useSync, method, uid, pwd);
name – local name used to identify the service url – SODA web service url fn - Callback function useSync - Activate Synchronous transfers method – method used for request; POST or GET uid - user id - for use with server-side login event when a connection is created pwd - user password - for use with server-side login event when a connection is created
getResponse();
Returns a
response object containing the returned value from the server and and error
object
For more information please see the IOElement Quick Reference Guide
Web Service Object Methods
call(name, params, fn); - calls a remote method on the server
name – name of method(s) on the server
params – parameters to pass to the method; multiple params are passed
as an array
fn – (optional) callback or returned function. When
set to false an synchronous call
is made.
importWebMethods(); - Import web methods available on the
server. Returns true if successful.
Example:
Let’s first create an IOElement with a single thread or port
var io = new IOElement(1); // for NS4 to support post request use IOElement(1,true);
Next we'll connect to the soda web service on the server
io.createWebService(‘book’, ‘bookmanager.asp’, initWS, false); function initWS(ws,s,et){ if(s!=false) { alert('Error while connecting'); return; } // some code here };
Request books from server
io.book.call(“getBooks”, null, fetchBooks);
function fetchBooks(e){ var o=e.getSource(); var result=o.getResult(); if (result.error) alert(result.error.text); else { var books=result.value; for( var i=0;i<books.length;i++){ // code here to display books } } }
Search for a book by the name of 'The JavaScript Bible'
var sortby=2; //author var query={}; query.name = ‘The JavaScript Bible’; query.author = ‘*’; query.year = ‘*’; io.book.call(‘searchBooks’,[query, sortby], fetchBooks);
The getBooks and searchBooks methods on the server-side can be written in any program.
Example of server-side code:
<!-- #include file=“soda.vbscript.asp” --> <%
Call wsAddMethod(“searchBooks”, Array(“name:string:*”, “sortby:int:0”),“object”) Call wsAddMethod(“getBooks”,null,“array”) Call wsDispatch()
Functions GetBooks() Dim books() ‘get data from database and populate books() array GetBooks=books End Function
Function SearchBooks(query, sortby) ‘ Note: In VBScript the dictionary object is used to ‘ represent an associative array Dim results // perform search SearchBooks = results End Function
%>
For more information please see:
<envelope> <sid>3435-453546-FG34-5464634</sid> <uid>Mary</uid> <pwd>password</pwd> <err>E1|System Error</err> <method>GetUsers</method> <body> <soda> <a0> <s1>This is a string</s1> <r0/> <s1>Testing A</s1> <r0/> <f1>34.5</f1> <r0/> <i1>100</i1> <r0/> <f1>0.15</f1> <r0/> <a1> <s2>A</s2> <r1/> <s2>B</s2> <r1/> <s2>C</s2> <r1/> <d2>3/20/2002 22:23:38</d2> </a1> <r0/> <s1>More string</s1> <r0/> <a1> <b2>true</b2> <r1/> <b2>false</b2> <r1/> <i2>0</i2> <r1/> <u2>0</u2> <r1/> <s2>Boolean</s2> </a1> <r0/> <o1> <a2> <s3>name|address|city|country|phone|email|fn</s3> <r2/> <a3> <s4>Mary Jane</s4> <r3/> <s4>34 More Lane</s4> <r3/> <s4>FL</s4> <r3/> <s4>USA</s4> <r3/> <u4>0</u4> <r3/> <s4>email@mail.com</s4> <r3/> <u4>0</u4> </a3> </a2> </o1> </a0> </soda> </body> </envelope>