Autor: Jean-Luc David
Data publikacji: 26.04.2005, 14:52 | Ostatnia modyfikacja: 19.11.2006, 17:45
ArtykuÅ‚ opisuje metody tworzenia usÅ‚ug WWW (webservices) umożliwiajÄ…cych komunikacjÄ™ przy pomocy protokoÅ‚u HTTP różnych aplikacji pracujÄ…cych na różnych platformach i stworzonych w różnych jÄ™zykach.
Originally published on XML.COM
Copyright (c)2005 Jean-Luc David / Stormpixel.com
Rozwój usÅ‚ug sieciowych (webservices) jest szeroko wspierany przez wszystkich gÅ‚ównych dziaÅ‚aczy i organizacje branży technologicznej, w tym przez IBM, Microsoft, Sun Microsystem oraz W3C. W tÄ™ gałąź zainwestowano do tej pory miliony dolarów. UsÅ‚ugi sieciowe pozwalajÄ… Ci wymieniać dane pomiÄ™dzy wieloma platformami i konfiguracjami sprzÄ™towymi. Na przykÅ‚ad możesz stworzyć usÅ‚ugÄ™ sieciowÄ… w jÄ™zyku Java, a ktoÅ› inny bÄ™dzie w stanie skorzystać w niej, używajÄ…c klienta pracujÄ…cego na platformie .NET bez koniecznoÅ›ci uczenia siÄ™ choćby podstaw Javy.
Wiele rozmaitych jÄ™zyków skryptowych wspiera tworzenie usÅ‚ug WWW. PHP jest jednym z nich i posiadajÄ… potężny arsenaÅ‚ caÅ‚kowicie darmowych funkcji i narzÄ™dzi stworzonych specjalnie do tego celu.
W tym artykule porównamy trzy metody tworzenia usÅ‚ug sieciowych: XML-RPC, SOAP oraz REST. ArtykuÅ‚ wymaga od czytelnika podstawowej znajomoÅ›ci specyfikacji usÅ‚ug sieciowych i PHP. Musisz mieć także dostÄ™p do serwera WWW udostÄ™pniajÄ…cego parser PHP, aby móc korzystać z podanych tu przykÅ‚adów. Jeżeli bÄ™dziesz potrzebować wiÄ™cej informacji, zajrzyj do spisu materiaÅ‚ów dodatkowych na koÅ„cu tekstu.
Remote Procedure Calls (RPC) są używane do ustanawiania i obsługi transakcji pomiędzy dwoma odległymi systemami. Przykładami popularnych implementacji RPC są DCOM i CORBA. XML-RPC jest precyzyjną implementacją RPC zezwalającą na przesyłanie danych XML między dwoma serwerami przy pomocy protokołu HTTP. W poniższych przykładach skorzystamy z wersji XML-RPC stworzonej przez Edda Dumbilla (http://xmlrpc.usefulinc.com/php.html).
Aby uaktywnić w PHP możliwość korzystania z XML-RPC, musisz ściągnąć XML-RPC Toolkit dostępny pod tym adresem:
http://sourceforge.net/project/showfiles.php?group_id=34455
GÅ‚ównymi plikami, których bÄ™dziemy używać, sÄ… xmlrpc.inc (gÅ‚ówna biblioteka) oraz xmlrpcs.inc (biblioteka serwera). A oto opis, jak zakodować prosty serwer XML-RPC przy wykorzystaniu PHP. Na poczÄ…tku dołączymy obydwie biblioteki:
<? include('xmlrpc.inc'); include('xmlrpcs.inc');
Następnie zdefiniujemy nową funkcję zwaną onttax(). Będzie ona udostępniana przez naszą usługę, a posłuży do obliczania piętnastoprocentowego federalnego i prowincjonalnego podatku VAT dla Ontario w Kanadzie, bazując na przekazanej kwocie w dolarach. Parametr odpowiadający kwocie w dolarach przekazywany jest do funkcji, a następnie konwertowany do postaci skalarnej (liczba, tekst). Gdy obliczenia zostały wykonane, tworzona jest odpowiedź (przy użyciu klasy xmlrpcresp) zawierająca wartość podatku VAT.
function onttax($par){ $amount=$par->getParam(0); $amountval=$amount->scalarval(); $taxcalc=$amountval*.15; return new xmlrpcresp(new xmlrpcval($taxcalc, 'string')); }
Teraz ustanawiamy serwer i oznaczamy naszą funkcję jako dostępną usługę WWW.
$server=new xmlrpc_server(array("taxcalc.onttax"=>array("function"=>"onttax"))); ?>
Teraz, gdy stworzyliśmy już serwer, przyszedł czas na zaprojektowanie klienta potrafiącego obsługiwać naszą usługę sieciową. Na początku musimy załączyć bibliotekę bazową, zdefiniować skalarną zmienną zwaną $amount i przypisać jej wartość $15.00.
<? include('xmlrpc.inc'); $amount='15.00';
NastÄ™pnie tworzymy instancjÄ™ klienta XML-RPC, który połączy siÄ™ z naszym serwerem. Wartość $amount jest do niego przesyÅ‚ana przy pomocy obiektu xmlrpcmsg:
$format=new xmlrpcmsg('taxcalc.onttax', array(new xmlrpcval($amount, 'double'))); $client=new xmlrpc_client('/xmlrpc-server.php', 'localhost', 80);
Gdy połączenie zostanie nawiÄ…zane, żądanie trafi na serwer do przetworzenia. Odpowiedź, czyli obliczona suma podatku, jest wtedy przekazywana z powrotem do $value. Konwertujemy jÄ… nastÄ™pnie na wartość skalarnÄ… i prezentujemy użytkownikowi. OczywiÅ›cie wcale nie trzeba siÄ™ tutaj zatrzymywać. Możesz bez problemu stworzyć klienta, który jeszcze dodatkowo przetworzy otrzymane dane.
$request=$client->send($format); $value=$request->value(); print $value->scalarval(); ?>
XML-RPC jest prostą i efektywną metodą transmisji danych XML. Został zaimplementowany w takich projektach, jak FreeNet, O'reilly's Meerkat, Syndic8, Google API i wielu innych aplikacjach. Jeżeli chcesz zdobyć o nim więcej wiadomości, odwiedź oficjalną stronę projektu: http://www.xmlrpc.com lub przeczytaj książkę "Programming Web Services with XML-RPC" (na polskim rynku jest ona w chwili obecnej niedostępna. przyp. tłum).
SOAP zostaÅ‚ zaprojektowany jako aplikacja XML dla usÅ‚ug sieciowych. Jego siÅ‚a leży w wykorzystaniu przestrzeni nazw, typów danych XML Schema oraz elastycznoÅ›ci transportu. Niestety specyfikacje i implementacja SOAP'a jest bardziej zÅ‚ożona, szczególnie w porównaniu do XML-RPC. Jest wykorzystywany gÅ‚ównie przez korporacyjnych twórców usÅ‚ug sieciowych. Intensywnie korzystajÄ… z niego np. Microsoft .NET oraz IBM WebSphere. Google i Amazon.com także wykorzystaÅ‚y jego popularność i uruchomiÅ‚y wÅ‚asne usÅ‚ugi SOAP.
NuSOAP jest potężnym API stworzonym dla platformy PHP. Pozwala Ci na tworzenie zarówno serwerów, jak i klientów. JednÄ… z jego najlepszych cech jest wbudowane wsparcie dla technologii WSDL. Instalacja NuSOAP jest prosta. Wszystko, czego potrzebujesz, to serwer z udostÄ™pnionym PHP. Wymagane biblioteki zawarte sÄ… w pliku nusoap.php. Zarówno dokumentacjÄ™, jak i ten plik możesz pobrać spod tego adresu: http://deitrich.ganx4.com/nusoap/.
Stworzenie klienta SOAP przy pomocy tej biblioteki jest bardzo proste. Aby pokazać, jak to wyglÄ…da, zdecydowaÅ‚em siÄ™ łączyć z usÅ‚ugÄ… sieciowÄ… udostÄ™pnionÄ… przez XMethods.net (http://www.xmethods.net). Znajduje siÄ™ tam szeroka gama użytecznych usÅ‚ug, z których możesz korzystać za darmo. W naszym przykÅ‚adzie skorzystamy z usÅ‚ugi konwertera walut, aby dowiedzieć siÄ™, jaki jest kurs wymiany miÄ™dzy amerykaÅ„skimi, a kanadyjskimi dolarami.
Oto pełna analiza kodu PHP niezbędnego do połączenia się z konwerterem. Na początek musimy dołączyć plik biblioteki. Komenda require_once() da nam pewność, iż stosowne funkcje zostaną dodane do skryptu tylko raz.
<? require_once('nusoap.php');
Następnym krokiem jest zdefiniowanie lokalizacji WSDL'a i utworzenie obiektu klasy soapclient, by otrzymać dostęp do usługi. WSDL oznacza Web Services Description Language (Język Opisu Usług Sieciowych) będący aplikacją XML opisującą interfejs usługi:
// Pamietajmy, ze w normalnych warunkach tego typu zmiennych tymczasowych nie powinnismy uzywac! $wsdl='http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl'; $client=new soapclient($wsdl, 'wsdl');
Teraz wyÅ›lemy poprzez utworzonego w ten sposób klienta dwa parametry zawierajÄ…ce nazwy dwóch krajów, których waluty chcemy porównać, aby otrzymać ich aktualny kurs. Użyjemy do tego funkcji getRate(). Wynik jest zwracany użytkownikowi.
$param=array( 'country1'=>'usa', 'country2'=>'canada' ); echo $client->call('getRate', $param); ?>
Aby lepiej wyjaśnić, co się dzieje podczas komunikacji między klientem, a serwerem SOAP, przedstawię przykładowy pakiet danych transmitowany od jednego do drugiego i vice versa. Najpierw nasz klient wysyła żądanie otrzymania pliku WSDL z serwera XMethods:
GET /sd/2001/CurrencyExchangeService.wsdl HTTP/1.0 Host: www.xmethods.net
Dokument ten jest przekazywany do naszego klienta SOAP. Zawiera definicje wszystkich metod dostępnych w usłudze CurrencyExchangeService:
HTTP/1.1 200 OK
Date: Tue, 10 Feb 2004 11:45:24 GMT
Server: Apache/1.3.26 (Unix) Enhydra-Director/3 PHP/4.0.6 DAV/1.0.3 AuthNuSphere/1.0.0
Last-Modified: Tue, 23 Oct 2001 18:10:37 GMT
ETag: "1981a8-654-3bd5b29d"
Accept-Ranges: bytes
Content-Length: 1620
Connection: close
Content-Type: text/xml
<?xml version="1.0"?>
<definitions name="CurrencyExchangeService"
targetNamespace="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl"
xmlns:tns="http://www.xmethods.net/sd/CurrencyExchangeService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="getRateRequest">
<part name="country1" type="xsd:string"/>
<part name="country2" type="xsd:string"/>
</message>
<message name="getRateResponse">
<part name="Result" type="xsd:float"/>
</message>
<portType name="CurrencyExchangePortType">
<operation name="getRate">
<input message="tns:getRateRequest" />
<output message="tns:getRateResponse" />
</operation>
</portType>
<binding name="CurrencyExchangeBinding" type="tns:CurrencyExchangePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getRate">
<soap:operation soapAction=""/>
<input >
<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="CurrencyExchangeService">
<documentation>Returns the exchange rate between the two currencies</documentation>
<port name="CurrencyExchangePort" binding="tns:CurrencyExchangeBinding">
<soap:address location="http://services.xmethods.net:80/soap"/>
</port>
</service>
</definitions>
Następnie klient przesyła dokładne żądanie użycia metody getRate(). Parametry są wysyłane według specyfikacji usługi sieciowej:
POST /soap HTTP/1.0
User-Agent: NuSOAP v0.6
Host: services.xmethods.net
Content-Type: text/xml
Content-Length: 622
SOAPAction: ""
<?xml version="1.0"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:si="http://soapinterop.org/xsd"
xmlns:galactivism="urn:xmethods-CurrencyExchange">
<SOAP-ENV:Body>
<galactivism:getRate>
<country1 xsi:type="xsd:string">usa</country1>
<country2 xsi:type="xsd:string">canada</country2>
</galactivism:getRate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
W koÅ„cowym etapie usÅ‚uga sieciowa odpowiada, przesyÅ‚ajÄ…c wynik żądania przekazanego w poprzedniej wiadomoÅ›ci. Nasz kurs walut miÄ™dzy KanadÄ… a USA wynosi 1,3267. Jest on wyÅ›wietlany bez nagÅ‚ówków SOAP.
HTTP/1.1 200 OK
Date: Tue, 10 Feb 2004 11:45:27 GMT
Server: Electric/1.0
Content-Type: text/xml
Content-Length: 492
X-Cache: MISS from www.xmethods.net
Connection: close
<?xml version='1.0' encoding='UTF-8'?>
<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:soapenc='http://schemas.xmlsoap.org/soap/encoding/'
soap:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
<soap:Body>
<n:getRateResponse xmlns:n='urn:xmethods-CurrencyExchange'>
<Result xsi:type='xsd:float'>1.3267</Result></n:getRateResponse>
</soap:Body>
</soap:Envelope>
Następny przykład pokaże, jak utworzyć serwer usług sieciowych w NuSOAP. Jedną z ciekawszych cech pakietu jest sieciowe zestawienie dostępnych usług oraz dynamicznie tworzone pliki WSDL dostępne z przeglądarki internetowej. Oto przykład takiego zestawienia:

Stworzymy teraz usÅ‚ugÄ™ CanadaTaxCalculator, która (podobnie jak w przykÅ‚adzie o XML-RPC) obliczy stawkÄ™ federalnego i prowincjonalnego podatku VAT dla Ontario w Kanadzie. Popatrzmy na kod:
<?php require_once('nusoap.php'); $ns='http://localhost/nusoap';
Na początku musimy dołączyć bibliotekę i zadeklarować przestrzeń nazw usługi. Zalecane jest wydzielenie osobnego adresu URI dla każdej z nich.
$server = new soap_server(); $server->configureWSDL('CanadaTaxCalculator',$ns); $server->wsdl->schemaTargetNamespace=$ns;
Teraz tworzymy serwer SOAP i definiujemy ustawienia naszego pliku WSDL takie, jak nazwa usługi oraz jej przestrzeń nazw.
$server->register('CalculateOntarioTax', array('amount' => 'xsd:string'), array('return' => 'xsd:string'), $ns);
NastÄ™pnie rejestrujemy naszÄ… funkcjÄ™ do obliczania podatku. W ten sposób powiadomimy serwer o jej istnieniu oraz o danych, jakie należy do niej przekazać. JeÅ›li masz kilka funkcji, musisz zarejestrować każdÄ… z nich z osobna.
function CalculateOntarioTax($amount){ $taxcalc=$amount*.15; return new soapval('return','string',$taxcalc); }
Na końcu uruchamiamy usługę przy pomocy następującej linijki:
$server->service($HTTP_RAW_POST_DATA); ?>
To wszystko. Zapisz ten kod w pliku server.php, umieść go na serwerze i voila! Aby wykonać podgląd dynamicznie wygenerowanych danych WSDL, wpisz następujący URL (oczywiście zastąp "localhost" przez nazwę twego serwera):
http://localhost/server.php?wsdl
W praktyce dodanie parametru ?wsdl do jakiegokolwiek serwera NuSOAP spowoduje wygenerowanie zestawienia. Oto, jak wyglÄ…da ono u nas:
<?xml version="1.0" encoding="ISO-8859-1" ?> <definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapinterop.org/xsd" xmlns:tns="http://localhost/nusoap" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://localhost/nusoap"> <types> <xsd:schema targetNamespace="http://localhost/nusoap"> <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" /> <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" /> </xsd:schema> </types> <message name="CalculateOntarioTaxRequest"> <part name="amount" type="xsd:string" /> </message> <message name="CalculateOntarioTaxResponse"> <part name="return" type="xsd:string" /> </message> <portType name="CanadaTaxCalculatorPortType"> <operation name="CalculateOntarioTax"> <input message="tns:CalculateOntarioTaxRequest" /> <output message="tns:CalculateOntarioTaxResponse" /> </operation> </portType> <binding name="CanadaTaxCalculatorBinding" type="tns:CanadaTaxCalculatorPortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> <operation name="CalculateOntarioTax"> <soap:operation soapAction="http://localhost/nusoap/onttaxws.php/CalculateOntarioTax" style="rpc" /> <input> <soap:body use="encoded" namespace="http://localhost/nusoap" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </input> <output> <soap:body use="encoded" namespace="http://localhost/nusoap" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" /> </output> </operation> </binding> <service name="CanadaTaxCalculator"> <port name="CanadaTaxCalculatorPort" binding="tns:CanadaTaxCalculatorBinding"> <soap:address location="http://localhost/nusoap/onttaxws.php" /> </port> </service> </definitions>
Co jednak, gdy zechcemy skorzystać z utworzonej przez nas usÅ‚ugi? Nie jest to problem. Stwórzmy jeszcze raz naszego klienta od zera. Po pierwsze, tworzymy obiekt klienta NuSOAP i przekazujemy adres do pliku WSDL z definicjami funkcji:
<?php require_once('nusoap.php'); $wsdl='http://localhost/server.php?wsdl'; $client=new soapclient($wsdl, 'wsdl');
NastÄ™pnie tworzymy zbiór parametrów i zdalnie wywoÅ‚ujemy funkcjÄ™ CalculateOntarioTax(). W tym przykÅ‚adzie wysyÅ‚amy kwotÄ™ $15.00, aby dowiedzieć siÄ™, jaki podatek bÄ™dziemy musieli od niej zapÅ‚acić w Ontario.
$param=array( 'amount'=>'15.00', ); echo $client->call('CalculateOntarioTax', $param); ?>
REST znaczÄ…co różni siÄ™ od SOAP i XML-RPC. Po pierwsze, nie jest to standard ani formalny, ani nieformalny. Nie istnieje do niego żadna ujednolicona biblioteka, czy też wbudowane klasy klienta i serwera dla PHP. W tym wÅ‚aÅ›nie drzemie siÅ‚a tego rozwiÄ…zania: nie potrzebujesz żadnych rozszerzeÅ„ i narzÄ™dzi do stworzenia usÅ‚ugi sieciowej. ProtokóÅ‚ HTTP zawiera już wszystko, czego potrzebujesz do transmisji i odbierania wiadomoÅ›ci XML.
REST, bÄ™dÄ…cy skrótem od "Representational State Transfer" reprezentuje znacznie prostsze podejÅ›cie do zagadnienia, niż XML-RPC i SOAP. Używa standardowych metod protokoÅ‚u HTTP takich, jak GET, POST i PUT do transmisji danych XML. Do ich dalszego przetworzenia możesz użyć takich narzÄ™dzi, jak PHP DOM, SAX, SimpleXML (PHP 5), a nawet XSL. WadÄ… jest to, iż wszystko trzeba napisać wÅ‚asnorÄ™cznie (mimo to w niektórych jÄ™zykach zaczynajÄ… siÄ™ pojawiać zestawy narzÄ™dzi i frameworki REST). Jeżeli chcesz projektować tego typu usÅ‚ugi, musisz orientować siÄ™ w tajnikach dziaÅ‚ania XML i HTTP oraz oczywiÅ›cie być przygotowanym na samodzielne pisanie trochÄ™ wiÄ™kszej iloÅ›ci kodu.
Do przesyÅ‚ania danych XML z jednego serwera do drugiego użyjemy moduÅ‚u PHP o nazwie cURL. Biblioteka Client URL Request Library jest zbiorem klas umożliwiajÄ…cych transfer i przesyÅ‚anie plików protokoÅ‚em HTTP. Dane sÄ… zapisane w formacie XML, zatem nie musimy tworzyć skomplikowanych serwerów. Nie sÄ… wymagane również żadne dodatkowe API, czy nakÅ‚adki. REST zwiÄ™ksza swÄ… popularność: Amazon.com stworzyÅ‚ bardzo popularnÄ… usÅ‚ugÄ™ sieciowÄ… zbudowanÄ… na bazie tej koncepcji.
Przyjrzyjmy siÄ™ kodowi klienta usÅ‚ugi REST. Na poczÄ…tku definiujemy lokalizacjÄ™ pliku. GdybyÅ› chciaÅ‚ wygenerować go dynamicznie, musisz jedynie stworzyć jakiÅ› plik PHP akceptujÄ…cy parametry w adresie URL, który wygeneruje i wyÅ›le jako rezultat dziaÅ‚ania wÅ‚aÅ›nie dane XML.
<? $rs='http://localhost/xmldata.xml'; $qs='';
NastÄ™pnie tworzymy tablicÄ™ z parametrami do przesÅ‚ania adresem URL. Wartość każdego z nich jest odpowiednio kodowana, dziÄ™ki czemu nie bÄ™dzie problemów z przesÅ‚aniem ich w nagÅ‚ówku HTTP:
$parray=array('amount'=>"15.00");$uri="$rs?$qs";
Teraz tworzymy obiekt cURL. Parametr CURLOPT_RETURNTRANSFER mówi, że chcemy przesÅ‚ać dane nawet w przypadku wystÄ…pienia błędów transmisji. Dalej wykonujemy całą operacjÄ™, a odpowiedź przekazujemy do zmiennej zwanej $xml:
$cobj=curl_init($uri); curl_setopt($cobj,CURLOPT_RETURNTRANSFER,1); $xml=curl_exec($cobj); curl_close($cobj); echo $xml; ?>
Oto kod serwera REST. Skrypt pobiera z adresu URL kwotę pieniędzy, oblicza podatek, po czym odsyła wynik w postaci XML:
<?php $taxcalc=$_GET["amount"]*.15; echo "<?xml version=\"1.0\"?>"; echo "<taxinfo>"; echo "<result>".$taxcalc."</result>"; echo "</taxinfo>"; ?>
Mamy trzy technologie oraz miliony pakietów narzÄ™dzi do tworzenia usÅ‚ug sieciowych. Nie ma zatem żadnych przeciwwskazaÅ„ dla wykorzystania PHP do tworzenia aplikacji bazujÄ…cych na XML'u. Upewnij siÄ™, że Å›ciÄ…gnÄ…Å‚eÅ› przykÅ‚adowy kod i ruszaj do akcji!
REST Wiki:
http://internet.conveyor.com/RESTwiki/
Specyfikacja SOAP:
http://www.w3.org/TR/SOAP/
Specyfikacje WDSL:
http://www.w3.org/TR/wsdl
Tłum: Zyx
Waszym zdaniem:
Nikt jeszcze nie dodał swojego komentarza. Możesz być pierwszy!