0

Accessing SOAP api's with YQL / Open Data Tables

Hi,

I'd like to access a soap api via yql and open data tables. Is there any tutorial or example script on how to do this?

Any help appreciated.

by
10 Replies
  • QUOTE (nexenator @ Feb 20 2010, 09:00 AM) <{POST_SNAPBACK}>
    Hi,

    I'd like to access a soap api via yql and open data tables. Is there any tutorial or example script on how to do this?

    Any help appreciated.



    There aren't any tutorials yet but there is a JS library I wrote to help with this.

    http://github.com/yql/yql-tables/blob/master/js/soap.js

    I'll try and get some documentation on it shortly. Let me know if you have any questions.
    0
  • QUOTE (sh1mmer @ Feb 20 2010, 05:42 PM) <{POST_SNAPBACK}>
    There aren't any tutorials yet but there is a JS library I wrote to help with this.

    http://github.com/yql/yql-tables/blob/master/js/soap.js

    I'll try and get some documentation on it shortly. Let me know if you have any questions.


    Thanks for the link.

    I copied the soap.js to the execute section but I had to remove the spawnParameters function in order to avoid a syntax error. Even then all I got was an error that the wsdl-file was not a valid xml object.

    these are the functions I use to invoke the soap-call:

    CODE
    function login_callBack(r)
    {
    if(r.constructor.toString().indexOf("function Error()") != -1){
    token = ("ERROR\r\n\r\n" + r.description + "\r\n\r\n[" + r.number + "]");
    } else {
    token = (r);
    searchProducts(token);
    }
    }
    function login(wsdl, method)
    {
    var username = '{username}';
    var password = '{password}';

    var WebServiceType = 'Product';

    var pl = new SOAPClientParameters();
    pl.add("Username", username);
    pl.add("Password", password);

    pl.add("WebServiceType", WebServiceType);
    SOAPClient.invoke(wsdl, method, pl, true, login_callBack);
    }


    Is there something wrong with the invoke?
    0
  • This is in the diagnostics if I use

    y.include('http:// ... my domain ../soap.js);

    CODE
    <diagnostics>
    ...
    <url execution-time="303" proxy="DEFAULT"><![CDATA[http:// -- mydomain -- .com/soap.js]]></url>
    <javascript><![CDATA[Error: missing } after property list<javascript>:377:spawnParameters ^: function() {]]></javascript>
    <javascript><![CDATA[Error: syntax error<javascript>:377:spawnParameters : ^function() {]]></javascript>
    <javascript><![CDATA[Error: syntax error<javascript>:380:}^;]]></javascript>
    <javascript><![CDATA[Error: syntax error<javascript>:381:}^();]]></javascript>
    <javascript><![CDATA[Exception: Compilation produced 4 syntax errors. (<javascript>#1)]]></javascript>
    ...
    </diagnostics>
    0
  • Ok, I'm getting further...

    There was a comma missing in the soap.js after the closing bracket of the invoke : function

    But after fixing that I still get the "Exception: TypeError [raw wsdl contents] is not an xml object" Error

    Can't figure out what's going wrong though
    0
  • And I found an other error in the soap.js

    On line 284 it should read:
    CODE
    var path = "response." + method + ".Result";


    Now I get an internal server-error from the soap server. However I can access the same server using php for example. So I guess there still is something wrong with the soap.js
    0
  • Ok I got the soap.js working with a simple soap api. I had to modify the soap.js - especially the return -> invoke function to make it work though.

    Here's the soap.js that works with the simple soap:
    CODE
    /*
    Javascript "SOAP Client" library

    Copyright (C) 2006 Matteo Casati http://www.guru4.net/
    Copyright (C) 2009 Tom Hughes-Croucher http://kid666.com/
    Copyright (C) 2010 Stephan Helbig http://istylr.com/

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    */

    SOAPClient = function() {

    SOAPClientParameters = function() {

    var pl = new Array();

    var serialize = function(o) {
    var s = "";
    switch (typeof(o))
    {
    case "string":
    s += o.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    break;
    case "number":
    case "boolean":
    s += o.toString();
    break;
    case "object":
    // Date
    if (o.constructor.toString().indexOf("function Date()") > -1) {
    var year = o.getFullYear().toString();
    var month = (o.getMonth() + 1).toString();
    month = (month.length == 1) ? "0" + month: month;
    var date = o.getDate().toString();
    date = (date.length == 1) ? "0" + date: date;
    var hours = o.getHours().toString();
    hours = (hours.length == 1) ? "0" + hours: hours;
    var minutes = o.getMinutes().toString();
    minutes = (minutes.length == 1) ? "0" + minutes: minutes;
    var seconds = o.getSeconds().toString();
    seconds = (seconds.length == 1) ? "0" + seconds: seconds;
    var milliseconds = o.getMilliseconds().toString();
    var tzminutes = Math.abs(o.getTimezoneOffset());
    var tzhours = 0;
    while (tzminutes >= 60) {
    tzhours++;
    tzminutes -= 60;
    }
    tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
    tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
    var timezone = ((o.getTimezoneOffset() < 0) ? "+": "-") + tzhours + ":" + tzminutes;
    s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
    } else if (o.constructor.toString().indexOf("function Array()") > -1) {
    // Array
    for (var p in o) {
    if (!isNaN(p)) {
    // linear array
    (/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
    var type = RegExp.$1;
    switch (type) {
    case "":
    type = typeof(o[p]);
    case "String":
    type = "string";
    break;
    case "Number":
    type = "int";
    break;
    case "Boolean":
    type = "bool";
    break;
    case "Date":
    type = "DateTime";
    break;
    }
    s += "<" + type + ">" + serialize(o[p]) + "</" + type + ">";
    } else {
    // associative array
    s += "<" + p + ">" + serialize(o[p]) + "</" + p + ">";
    }
    }
    } else {
    // Object or custom function
    for (var p in o) {
    s += "<" + p + ">" + serialize(o[p]) + "</" + p + ">";
    break;
    }
    }
    default:
    break;
    // throw new Error(500, "SOAPClientParameters: type '" + typeof(o) + "' is not supported");
    }
    return s;
    };

    return {
    add : function(name, value) {
    pl[name] = value;
    },

    toXml : function() {

    default xml namespace = "";
    var xml = <></>;
    for(var p in pl)
    {
    switch(typeof(pl[p]))
    {
    case "string":
    case "number":
    case "boolean":
    case "object":
    xml += <{p}>{serialize(pl[p])}</{p}>;
    break;
    default:
    break;
    }
    }
    return xml;
    }
    };
    };

    var username = null;
    var password = null;

    var wsdlCache = [];

    var toBase64 = function(input) {
    var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    var output = "";
    var chr1,
    chr2,
    chr3;
    var enc1,
    enc2,
    enc3,
    enc4;
    var i = 0;

    do {
    chr1 = input.charCodeAt(i++);
    chr2 = input.charCodeAt(i++);
    chr3 = input.charCodeAt(i++);

    enc1 = chr1 >> 2;
    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
    enc4 = chr3 & 63;

    if (isNaN(chr2)) {
    enc3 = enc4 = 64;
    } else if (isNaN(chr3)) {
    enc4 = 64;
    }

    output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
    keyStr.charAt(enc3) + keyStr.charAt(enc4);
    }
    while (i < input.length);

    return output;
    };



    var onSendSoapRequest = function(method, wsdl, response) {

    //get namespace
    var ns = wsdl.@["targetNamespace"];

    var path = "response.." + method + "Result";




    default xml namespace = ns;
    var nd = eval(path);


    return nd;
    };

    var sendSoapRequest = function(url, method, parameters, wsdl) {

    // get namespace
    default xml namespace = "http://schemas.xmlsoap.org/wsdl/http/";
    ns = wsdl.@["targetNamespace"];

    // build SOAP request
    var soap = new Namespace('http://schemas.xmlsoap.org/wsdl/soap/');
    var sr = <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><{method} xmlns={ns}>{parameters.toXml()}</{method}></soap:Body></soap:Envelope>;

    //var post = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + sr.toString();
    postvals = sr;
    var xmlHttp = y.rest(url);

    if (SOAPClient.username && SOAPClient.password) {
    // Some WS implementations (i.e. BEA WebLogic Server 10.0 JAX-WS) don't support Challenge/Response HTTP BASIC, so we send authorization headers in the first request
    xmlHttp.header("Authorization", "Basic " + toBase64(username + ":" + password));
    }

    if (ns.lastIndexOf(/\//) != ns.length - 1) {
    var soapaction = ns + "/" + method;
    } else {
    var soapaction = ns + method;
    }
    xmlHttp.header("SOAPAction", soapaction);
    xmlHttp.header("Content-Type", "text/xml; charset=utf-8");
    xmlHttp.accept("application/xml");

    var response = xmlHttp.post(postvals).response;

    return response;
    };

    var loadWsdl = function(url, method, parameters) {
    var wsdl = wsdlCache[url];
    //Cache disabled
    // if available get from cache
    // if(wsdl + "" != "" && wsdl + "" != "undefined") {
    // return wsdl;
    // } else {
    // otherwise get wsdl and cache it
    if(url.indexOf('?wsdl') != -1){
    var xmlHttp = y.rest(url);
    } else {
    var xmlHttp = y.rest(url + "?wsdl");
    }

    wsdl = xmlHttp.get().response;

    wsdlCache[url] = wsdl;

    return wsdl;

    // }

    };

    return {
    invoke : function(url, method, parameters) {
    wsdl = loadWsdl(url, method, parameters);

    var response = sendSoapRequest(url, method, parameters, wsdl);
    return response;

    // var obj = onSendSoapRequest(method, wsdl, response);

    var response2 = <></>;
    response2 += obj.*;

    // return response2;// + ' / '+response;

    //o = soapresult2object(nd, wsdl);
    },

    spawnParameters : function() {
    return new SOAPClientParameters;
    }
    };
    }();


    I still can't access the api of my needs though. Basicly I try to do the following with yql:
    Working PHP-Code:
    CODE
    <?php

    /* <LIVE DATA>
    define ("WSDL_LOGON", "https://api.affili.net/V2.0/Logon.svc?wsdl");
    define ("WSDL_PROD", "https://api.affili.net/V2.0/ProductServices.svc?wsdl");

    $Username = ""; // the publisher ID
    $Password = ""; // the product data web services password

    $SOAP_LOGON = new SoapClient(WSDL_LOGON);
    $Token = $SOAP_LOGON->Logon(array(
    'Username' => $Username,
    'Password' => $Password,
    'WebServiceType' => 'Product'
    ));
    </LIVE DATA> */

    /* <DEMO DATA> */
    define ("WSDL_LOGON", "https://developer-api.affili.net/V2.0/Logon.svc?wsdl");
    define ("WSDL_PROD", "https://developer-api.affili.net/V2.0/ProductServices.svc?wsdl");

    $Username = ''; // your developer ID
    $Password = ''; // your developer portal password
    $DemoPublisherId = 403233; // one of the publisher IDs of our demo database
    $DeveloperSettings = array('SandboxPublisherID' => $DemoPublisherId);

    $SOAP_LOGON = new SoapClient(WSDL_LOGON);
    $Token = $SOAP_LOGON->Logon(array(
    'Username' => $Username,
    'Password' => $Password,
    'WebServiceType' => 'Product',
    'DeveloperSettings' => $DeveloperSettings
    ));
    /*</DEMO DATA> */

    $params = array(
    'ShopIds' => array('0'),
    'Query' => 'jeans',
    'WithImageOnly' => true,
    'Details' => 'true',
    'ImageSize' => 'AllImages',
    'CurrentPage' => '1',
    'PageSize' => '10',
    'MinimumPrice' => '0',
    'MaximumPrice' => '0',
    'SortBy' => 'Rank',
    'SortOrder' => 'Descending'
    );
    $SOAP_REQUEST = new SoapClient(WSDL_PROD);
    $req = $SOAP_REQUEST->SearchProducts(array(
    'CredentialToken' => $Token,
    'SearchProductsRequestMessage' => $params
    ));

    print_r($req);

    ?>


    When I call the later api with the soap.js all I recieve is a 500 internal server error and I suspect that it is caused by the parameters. The affili.net api needs an array as wrapper:
    CODE
    $Token      = $SOAP_LOGON->Logon(array(
    'Username' => $Username,
    'Password' => $Password,
    'WebServiceType' => 'Product'
    ));



    This is my execute statement in the open data table:

    CODE
    y.include('http:// my-domain .com/soap.js);

    var token;

    function login()
    {

    var WebServiceType = 'Product';

    var DeveloperSettings = new Object;
    DeveloperSettings['SandboxPublisherID'] = 403233;

    var pl = new SOAPClientParameters;
    pl.add("Username", username);
    pl.add("Password", password);

    pl.add("WebServiceType", WebServiceType);
    pl.add("DeveloperSettings", DeveloperSettings);

    return SOAPClient.invoke('https://developer-api.affili.net/V2.0/Logon.svc', "Logon", pl);
    }

    token = login();


    And the yql-console-diagnostics return the following:

    CODE
     <diagnostics>
    <publiclyCallable>true</publiclyCallable>
    <url execution-time="437" proxy="DEFAULT"><![CDATA[http:// my-domain .com/yql-affilinet-product-search.xml?534]]></url>
    <url execution-time="336" proxy="DEFAULT"><![CDATA[http:// my-domain .com/soap.js?rand=0]]></url>
    <url execution-time="661" proxy="DEFAULT"><![CDATA[https://developer-api.affili.net/V2.0/Logon.svc?wsdl]]></url>
    <url execution-time="104" http-status-code="500" http-status-message="Internal Server Error" proxy="DEFAULT"><![CDATA[https://developer-api.affili.net/V2.0/Logon.svc]]></url>
    <javascript execution-time="1107" instructions-used="14500" table-name="products"/>
    <user-time>1561</user-time>
    <service-time>1538</service-time>
    <build-version>4265</build-version>
    </diagnostics>


    Does anybody know how to solve this?

    Any help is appreciated!

    Stephan
    0
  • I believe that the soap.js is intended to access SOAP endpoints directly, not through the WSDL definition of the SOAP endpoint.

    Sam
    0
  • QUOTE (Sam @ Feb 22 2010, 09:19 AM) <{POST_SNAPBACK}>
    I believe that the soap.js is intended to access SOAP endpoints directly, not through the WSDL definition of the SOAP endpoint.

    Sam


    No the soap.js perfectly parses the wsdl and builds the envelope
    0
  • QUOTE (nexenator @ Feb 22 2010, 09:25 AM) <{POST_SNAPBACK}>
    No the soap.js perfectly parses the wsdl and builds the envelope


    Hey, I'm actually the owner/maintainer of that library, but I never had enough time to properly test it through with more than a couple of end-points. Can you email me off boards and we can get some debugging going to figure it out?

    croucher at yahoo hyphen inc dot com

    Thanks :)
    0
  • Sorry for posting so much. But I'm desperately searching for a solution :(What can I or the api-owner or yahoo do in order to get around this?
    0

Recent Posts

in YQL