SOAP Protocol and Web Services. SOAP protocol

  • Tutorial

Hi all!
It so happened that recently I began to develop web services. But today the topic is not about me, but about how we can write our own XML Web Service based on the SOAP 1.2 protocol.

I hope that after reading the topic you will be able to:

  • write your own server implementation of a web application;
  • write your own client implementation of a web application;
  • write your own web service description (WSDL);
  • send the client arrays of the same type of data to the server.
As you might have guessed, all the magic will be done using PHP and the built-in SoapClient and SoapServer classes. Our rabbit will be a service for sending SMS messages.

1 Problem statement

1.1 Boundaries

At the beginning, I propose to deal with the result that we will achieve at the end of the topic. As announced above, we will write a service for sending SMS messages, and more precisely, we will receive messages from different sources via the SOAP protocol. After which, we will consider in what form they come to the server. The process of queuing messages for further sending to the provider, unfortunately, is beyond the scope of this post for many reasons.

1.2 What data will we change?

Great, we have decided on the boundaries! The next step that needs to be taken is to decide what data we will exchange between the server and the client. On this topic, I suggest not to split hairs for too long and immediately answer the main questions for yourself:
  • What minimum data must be sent to the server in order to send an SMS message to a subscriber?
  • What minimum data must be sent from the server to satisfy the client's needs?
Something tells me that for this you need to send the following:
  • mobile phone number and
  • text of the SMS message.
In principle, these two characteristics are enough for sending, but I immediately imagine the case of an SMS with birthday greetings coming to you at 3 o’clock in the morning, or 4! At this moment, I will be very grateful to everyone for not forgetting about me! Therefore, we will also send to the server and
  • date of sending the SMS message.
The next thing I would like to send to the server is:
  • Message type.
This parameter is not mandatory, but it can be very useful to us if we quickly need to tell the boss how many of our clients we have “delighted” with our news, and also draw some beautiful statistics on this matter.

And yet, I forgot something! If we reflect a little more, it is worth noting that the client can send either one SMS message or a number of them to the server at a time. In other words, one data packet can contain from one to infinity messages.

As a result, we get that to send an SMS message we need the following data:

  • mobile phone number,
  • SMS message text,
  • time of sending the SMS message to the subscriber,
  • message type.

We have answered the first question, now we need to answer the second question. And perhaps I’ll allow myself to mess around a little. Therefore, from the server we will send only Boolean data, the meaning of which has the following meaning:

  • TRUE – the packet successfully reached the server, passed authentication and queued for sending to the SMS provider
  • FALSE – in all other cases

This concludes the description of the problem statement! And finally, let's get down to the fun part - let's figure out what kind of strange beast this SOAP is!

2 What is SOAP?

In general, initially I did not plan to write anything about what SOAP is and wanted to limit myself to links to the w3.org website with the necessary specifications, as well as links to Wikipedia. But at the very end I decided to write a short note about this protocol.

And I will begin my story with the fact that this data exchange protocol belongs to a subset of protocols based on the so-called RPC (Remote Procedure Call) paradigm, the antipode of which is REST (Representational State Transfer). You can read more about this on Wikipedia; links to articles are at the very end of the topic. From these articles, we need to understand the following: “The RPC approach allows the use of a small number of network resources with a large number of methods and a complex protocol. With the REST approach, the number of methods and protocol complexity are strictly limited, which means the number of individual resources can be large.” That is, in relation to us, this means that in the case of the RPC approach on the site there will always be one input (link) to the service and what procedure to call to process incoming data we transfer along with the data, while with the REST approach in our The site has many inputs (links), each of which accepts and processes only certain data. If anyone reading knows how to explain the difference in these approaches even more simply, be sure to write in the comments!

The next thing we need to know about SOAP is that this protocol uses the same XML as a transport, which on the one hand is very good, because Our arsenal immediately includes the full power of a stack of technologies based on this markup language, namely XML-Schema - a language for describing the structure of an XML document (thanks Wikipedia!), which allows automatic validation of data received by the server from clients.

And so, now we know that SOAP is a protocol used to implement remote procedure calls and it uses XML as a transport! If you read the article on Wikipedia, you can also learn from there that it can be used over any application-level protocol, and not just in combination with HTTP (unfortunately, in this topic we will only consider SOAP over HTTP). And you know what I like most about all this? If there are no guesses, then I will give a hint - SOAP!... Still no guesses?... Are you sure you read the article on Wikipedia?... In general, I won’t torture you further. Therefore, I’ll go straight to the answer: “SOAP (from the English Simple Object Access Protocol - simple protocol access to objects; up to specification 1.2)". The most remarkable thing about this line is in italics! I don’t know what conclusions you drew from all this, but I see the following - since this protocol cannot in any way be called “simple” (and apparently even w3 agrees with this), then from version 1.2 it stopped being decrypted somehow! And it became known as SOAP, just SOAP, period.

Well, okay, please excuse me, I got a little sidetracked. As I wrote earlier, XML is used as transport, and the packets that travel between the client and the server are called SOAP envelopes. If you consider the general structure of the envelope, it will seem very familiar to you, because... resembles the structure of an HTML page. It has a main section - Envelop, which includes sections Header And Body, or Fault. IN Body data is transmitted and it is a mandatory section of the envelope, while Header is optional. IN Header authorization or any other data that is not directly related to the input data of the web service procedures may be transmitted. About Fault there is nothing special to tell, except that it comes to the client from the server in case of any errors.

This is where my review story about the SOAP protocol ends (we will look at the envelopes themselves and their structure in more detail when our client and server finally learn to run them at each other) and a new one begins - about the SOAP companion called WSDL(Web Services Description Language). Yes, yes, this is the very thing that scares most of us away from even trying to implement our API on this protocol. As a result, we usually reinvent our wheel with JSON as transport. So what is WSDL? WSDL is a language for describing web services and accessing them, based on the XML language (c) Wikipedia. If this definition does not make clear to you the entire sacred meaning of this technology, then I will try to describe it in my own words!

WSDL is designed to allow our clients to communicate normally with the server. To do this, the file with the extension “*.wsdl” describes the following information:

  • What namespaces were used?
  • What data schemas were used?
  • What types of messages does the web service expect from clients?
  • Which data belongs to which web service procedures,
  • What procedures does the web service contain?
  • How should the client call the web service procedures,
  • To which address should customer calls be sent?
As you can see, this file is the entire web service. By specifying the address of the WSDL file in the client, we will know everything about any web service! As a result, we do not need to know absolutely nothing about where the web service itself is located. All you need to know is the location of its WSDL file! We will soon find out that SOAP is not as scary as Russian proverbs make it out to be.

3 Introduction to XML-Schema

Now we know a lot about what SOAP is, what is inside it, and have an overview of the technology stack that surrounds it. Since, first of all, SOAP is a method of interaction between a client and a server, and XML markup language is used as a transport for it, in this section we will understand a little about how automatic data validation occurs using XML schemas.

The main purpose of the diagram is to describe the structure of the data that we are going to process. All data in XML schemas is divided into simple(scalar) and complex(structures) types. Simple types include the following types:

  • line,
  • number,
  • boolean value,
  • date.
Something very simple that has no extensions inside. Their antipode is complex complex types. The simplest example of a complex type that comes to everyone’s mind is objects. For example, a book. The book consists of properties: author, Name, price, ISBN number etc. And these properties, in turn, can be either simple types or complex ones. And the task of the XML schema is to describe this.

I suggest not going far and writing an XML schema for our SMS message! Below is the xml description of the SMS message:

71239876543 Test message 2013-07-20T12:00:00 12
Our complex type diagram will look like this:


This entry reads as follows: We have a variable " message" type " Message" and there is a complex type called " Message", which consists of a sequential set of elements " phone" type string, « text" type string, « date" type dateTime, « type" type decimal. These types are simple and are already defined in the schema description. Congratulations! We just wrote our first XML Schema!

I think that the meaning of the elements " element" And " complexType"Everything has become more or less clear to you, so we won’t focus on them any more and let’s switch straight to the composer element" sequence" When we use the composer element " sequence“We inform you that the elements included in it must always be located in the sequence specified in the diagram, and all of them are mandatory. But don't despair! There are two more composer elements in XML schemas: " choice" And " all" Composer " choice" announces that there must be one of the elements listed in it, and the composer " all» – any combination of the listed elements.

As you remember, in the first section of the topic we agreed that from one to infinity SMS messages can be transmitted in a package. Therefore, I propose to understand how such data is declared in the XML schema. The general package structure might look like this:

71239876543 Test message 1 2013-07-20T12:00:00 12 71239876543 Test message N 2013-07-20T12:00:00 12
The diagram for such a complex type will look like this:


The first block contains the familiar declaration of the complex type “ Message" If you noticed, then in each simple type included in " Message", new clarifying attributes have been added " minOccurs" And " maxOccurs" As you might guess from the name, the first ( minOccurs) indicates that this sequence must contain at least one element of type " phone», « text», « date" And " type", while the next one ( maxOccurs) attribute declares to us that there is at most one such element in our sequence. As a result, when we write our own schemas for any data, we are given the widest choice in how to configure them!

The second block of the diagram declares the element " messageList" type " MessageList" It is clear that " MessageList" is a complex type that contains at least one element " message", but the maximum number of such elements is not limited!

4 Write your WSDL

Do you remember that WSDL is our web service? I hope you remember! As we write it, our little web service will run on it. Therefore, I suggest not to mess around.

In general, in order for everything to work correctly for us, we need to transfer a WSDL file with the correct MIME type to the client. To do this, you need to configure your web server accordingly, namely, set the MIME type for files with the “*.wsdl” extension to the following line:

Application/wsdl+xml
But in practice, I usually sent the HTTP header via PHP " text/xml»:

Header("Content-Type: text/xml; charset=utf-8");
and everything worked great!

I want to warn you right away that our simple web service will have a rather impressive description, so don’t be alarmed, because... Most of the text is obligatory water and, having written it once, you can constantly copy it from one web service to another!

Since WSDL is XML, you need to write about this directly in the very first line. The root element of the file should always be named " definitions»:


Typically, WSDL consists of 4-5 main blocks. The very first block is the definition of a web service or, in other words, the entry point.


It says here that we have a service called “ SmsService" In principle, all the names in the WSDL file can be changed by you to whatever you want, because they play absolutely no role.

After this we announce that in our web service " SmsService" there is an entry point ("port") called " SmsServicePort" It is to this entry point that all requests from clients to the server will be sent. And indicate in the element “ address» link to the handler file that will accept requests.

Once we have defined the web service and specified the entry point for it, we need to bind supported procedures to it:


To do this, it lists which operations and in what form they will be called. Those. for port " SmsServicePort" a binding is defined under the name " SmsServiceBinding", which has a call type " rpc"and HTTP is used as the transfer protocol. Thus, we indicated here that we will make an RPC call over HTTP. After this we describe which procedures ( operation) are supported in the web service. We will support only one procedure – “ sendSms" Through this procedure our wonderful messages will be sent to the server! After the procedure has been declared, it is necessary to indicate in what form the data will be transmitted. In this case, it is indicated that standard SOAP envelopes will be used.

After that, we need to bind the procedure to messages:


To do this, we specify that our binding is of type " SmsServicePortType" and in the element " portType"with the name of the same type, we indicate the binding of procedures to messages. And so, the incoming message (from client to server) will be called “ sendSmsRequest", and outgoing (from server to client) " sendSmsResponse" Like all names in WSDL, the names of incoming and outgoing messages are arbitrary.

Now we need to describe the messages themselves, i.e. incoming and outgoing:


To do this we add the elements " message" with names " sendSmsRequest" And " sendSmsResponse" respectively. In them we indicate that the input should be an envelope whose structure corresponds to the data type " Request" After which an envelope is returned from the server containing the data type - “ Response».

Now we need to do just a little - add a description of these types to our WSDL file! And how do you think the WSDL describes incoming and outgoing data? I think that you have already understood everything a long time ago and told yourself that using XML schemas! And you will be absolutely right!


You can congratulate us! Our first WSDL has been written! And we are one step closer to achieving our goal.
Next, we'll look at what PHP provides us with for developing our own distributed applications.

5 Our first SOAP server

Earlier I wrote that to create a SOAP server in PHP we will use the built-in SoapServer class. In order for all further actions to happen the same way as for me, you will need to tweak your PHP a little. To be even more precise, you need to make sure that you have the “php-soap” extension installed. It is best to read how to install it on your web server on the official PHP website (see the list of references).

After everything has been installed and configured, we will need to create a file in the root folder of your hosting “ smsservice.php» with the following content:

setClass("SoapSmsGateWay"); //Start the server $server->handle();
I hope there is no need to explain what is above the line with the “ini_set” function. Because there it is determined which HTTP headers we will send from the server to the client and the environment is configured. In the line with “ini_set” we disable caching of the WSDL file so that our changes in it immediately take effect on the client.

Now we come to the server! As you can see, the entire SOAP server takes only three lines! On the first line, we create a new instance of the SoapServer object and pass the address of our WSDL description of the web service to its constructor. Now we know that it will be located in the root of the hosting in a file with the self-explanatory name “ smsservice.wsdl.php" In the second line, we tell the SOAP server which class needs to be pulled in order to process the envelope received from the client and return the envelope with the response. As you might have guessed, it is in this class that our only method will be described sendSms. On the third line we start the server! That's it, our server is ready! With which I congratulate us all!

Now we need to create the WSDL file. To do this, you can either simply copy its contents from the previous section, or take liberties and “template” it a little:

"; ?> /" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http:// schemas.xmlsoap.org/wsdl/http/" name="SmsWsdl" xmlns="http://schemas.xmlsoap.org/wsdl/"> /"> /smsservice.php" />
At this stage, we should be completely satisfied with the resulting server, because We can log the envelopes coming to it and then calmly analyze the incoming data. In order for us to receive anything on the server, we need a client. So let's get to it!

6 SOAP client on the way

First of all, we need to create a file in which we will write the client. As usual, we will create it in the root of the host and call it " client.php", and inside we will write the following:

messageList = new MessageList(); $req->messageList->message = new Message(); $req->messageList->message->phone = "79871234567"; $req->messageList->message->text = "Test message 1"; $req->messageList->message->date = "2013-07-21T15:00:00.26"; $req->messageList->message->type = 15; $client = new SoapClient("http://($_SERVER["HTTP_HOST"])/smsservice.wsdl.php", array("soap_version" => SOAP_1_2)); var_dump($client->sendSms($req));
Let's describe our objects. When we wrote the WSDL, it described three entities for the envelope incoming to the server: Request, MessageList And Message. Accordingly classes Request, MessageList And Message are reflections of these entities in our PHP script.

Once we have defined the objects, we need to create an object ( $req), which we will send to the server. After which come the two most cherished lines for us! Our SOAP client! Believe it or not, this is enough for our server to start receiving messages from the client, as well as for our server to successfully receive and process them! In the first of them, we create an instance of the SoapClient class and pass the address of the location of the WSDL file to its constructor, and in the parameters we explicitly indicate that we will work using the SOAP protocol version 1.2. On the next line we call the method sendSms object $client and immediately display the result in the browser.
Let's run it and see what we finally got!

The following object was returned to me from the server:

Object(stdClass) public "status" => boolean true
And this is great, because... Now we know for sure that our server is working and not only works, but can also return some values ​​to the client!

Now let's look at the log that we prudently keep on the server side! In its first part we see the raw data that arrived on the server:

79871234567 Test message 1 2013-07-21T15:00:00.26 15
This is the envelope. Now you know what it looks like! But it’s unlikely that we’ll be interested in looking at it all the time, so let’s deserialize the object from the log file and see if everything is fine:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1 " (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length=2)
As you can see, the object was deserialized correctly, for which I want to congratulate us all! Something more interesting awaits us next! Namely, we will send the client to the server not just one SMS message, but a whole pack (to be more precise, three)!

7 Sending complex objects

Let's think about how we can transfer a whole bunch of messages to the server in one packet? Probably the easiest way would be to organize an array inside the messageList element! Let's do this:

// create an object to send to the server $req = new Request(); $req->messageList = new MessageList(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList->message = $msg1; $req->messageList->message = $msg2; $req->messageList->message = $msg3;
Our logs indicate that the following packet was received from the client:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
What nonsense, you say? And you will be right in a sense, because... As soon as we learned that an object left the client, it came to our server in absolutely the same form in the form of an envelope. True, SMS messages were not serialized in XML in the way we needed - they had to be wrapped in elements message, not in Struct. Now let's see in what form such an object comes to the method sendSms:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "Struct" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
What does this knowledge give us? Only that the path we chose is not correct and we did not receive an answer to the question - “How can we get the correct data structure on the server?” But I suggest not to despair and try to convert our array to the type object:

$req->messageList->message = (object)$req->messageList->message;
In this case, we will receive another envelope:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
Came into the method sendSms the object has the following structure:

Object(stdClass) public "messageList" => object(stdClass) public "message" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public " type" => string "15" (length=2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length= 37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone " => string "79871234567" (length=11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length= 19) public "type" => string "17" (length=2)
As for me, “the sum does not change from changing the places of the terms” (c). What BOGUS, What Struct– we have not yet achieved our goal! And to achieve it, we need to make sure that instead of these incomprehensible names our native one is displayed message. But the author does not yet know how to achieve this. Therefore, the only thing we can do is get rid of the extra container. In other words, we will now make sure that instead of message became BOGUS! To do this, change the object as follows:

// create an object to send to the server $req = new Request(); $msg1 = new Message(); $msg1->phone = "79871234567"; $msg1->text = "Test message 1"; $msg1->date = "2013-07-21T15:00:00.26"; $msg1->type = 15; $msg2 = new Message(); $msg2->phone = "79871234567"; $msg2->text = "Test message 2"; $msg2->date = "2014-08-22T16:01:10"; $msg2->type = 16; $msg3 = new Message(); $msg3->phone = "79871234567"; $msg3->text = "Test message 3"; $msg3->date = "2014-08-22T16:01:10"; $msg3->type = 17; $req->messageList = $msg1; $req->messageList = $msg2; $req->messageList = $msg3; $req->messageList = (object)$req->messageList;
What if we get lucky and the correct name comes up from the diagram? To do this, let's look at the envelope that arrived:

79871234567 Test message 1 2013-07-21T15:00:00.26 15 79871234567 Test message 2 2014-08-22T16:01:10 16 79871234567 Test message 3 2014-08-22T16:01:10 17
Yes, a miracle did not happen! BOGUS– we won’t win! Came to sendSms the object in this case will look like this:

Object(stdClass) public "messageList" => object(stdClass) public "BOGUS" => array (size=3) 0 => object(stdClass) public "phone" => string "79871234567" (length=11) public " text" => string "Test message 1" (length=37) public "date" => string "2013-07-21T15:00:00.26" (length=22) public "type" => string "15" (length =2) 1 => object(stdClass) public "phone" => string "79871234567" (length=11) public "text" => string "Test message 2" (length=37) public "date" => string " 2014-08-22T16:01:10" (length=19) public "type" => string "16" (length=2) 2 => object(stdClass) public "phone" => string "79871234567" (length= 11) public "text" => string "Test message 3" (length=37) public "date" => string "2014-08-22T16:01:10" (length=19) public "type" => string " 17" (length=2)
As they say – “Almost”! On this (slightly sad) note, I propose to slowly wrap things up and draw some conclusions for ourselves.

8 Conclusion

Finally we got here! Let's figure out what you can do now:
  • you can write the WSDL file necessary for your web service;
  • you can easily write your own client that can communicate with the server via SOAP;
  • you can write your own server that communicates with the outside world via SOAP;
  • you can send arrays of the same type of objects to the server from your client (with some restrictions).
We also made some discoveries during our little research:
  • the native SoapClient class does not correctly serialize data structures of the same type in XML;
  • when serializing an array to XML it creates an extra element called Struct;
  • when serializing an object to XML it creates an extra element called BOGUS;
  • BOGUS less evil than Struct due to the fact that the envelope is more compact (extra namespaces are not added to the XML header of the envelope);
  • Unfortunately, the SoapServer class does not automatically validate the envelope data with our XML schema (perhaps other servers do not do this either).

The topic title is really a question, because... I myself don’t know what it is and for the first time I will try to work with it within the framework of this article. The only thing I can guarantee is that the code presented below will work, but my phrases will only be assumptions and guesses about how I myself understand all this. So, let's go...

Introduction

We need to start with why the concept of web services was created. By the time this concept appeared in the world, technologies already existed that allowed applications to interact at a distance, where one program could call some method in another program, which could be launched on a computer located in another city or even country. All this is abbreviated as RPC (Remote Procedure Calling). Examples include CORBA technologies, and for Java - RMI (Remote Method Invoking). And everything seems to be good in them, especially in CORBA, because... You can work with it in any programming language, but something was still missing. I believe that the disadvantage of CORBA is that it works through some of its own network protocols instead of simple HTTP, which will fit through any firewall. The idea of ​​the web service was to create an RPC that would be inserted into HTTP packets. Thus began the development of the standard. What are the basic concepts of this standard:
  1. SOAP. Before calling a remote procedure, you need to describe this call in an XML file in SOAP format. SOAP is simply one of the many XML markups that are used in web services. Everything we want to send somewhere via HTTP is first converted into an XML SOAP description, then stuffed into an HTTP packet and sent to another computer on the network via TCP/IP.
  2. WSDL. There is a web service, i.e. a program whose methods can be called remotely. But the standard requires that this program be accompanied by a description that says that “yes, you’re right – this is really a web service and you can call such and such methods from it.” This description is represented by another XML file, which has a different format, namely WSDL. Those. WSDL is just an XML file describing a web service and nothing more.
Why so briefly you ask? Can't you be more specific? It’s probably possible, but to do this you’ll have to turn to books such as T. Mashnin, “Java Web Services.” There, over the first 200 pages, there is a detailed description of each tag of the SOAP and WSDL standards. Is it worth doing? In my opinion, no, because... all this is created automatically in Java, and you only need to write the contents of the methods that are supposed to be called remotely. So, an API such as JAX-RPC appeared in Java. If anyone doesn't know, when they say that Java has such and such an API, it means that there is a package with a set of classes that encapsulate the technology in question. JAX-RPC evolved over time from version to version and eventually became JAX-WS. WS obviously stands for WebService and one might think that this is simply a renaming of RPC as a popular buzzword these days. This is not true, because Now web services have moved away from the original idea and allow you not only to call remote methods, but also to simply send document messages in SOAP format. I don’t know why this is needed yet; it’s unlikely that the answer here will be “just in case it’s needed.” I myself would like to learn from more experienced comrades. And lastly, then JAX-RS appeared for so-called RESTful web services, but this is the topic of a separate article. The introduction can end here, because... Next we will learn to work with JAX-WS.

General approach

In web services there is always a client and a server. The server is our web service and is sometimes called the endpoint (as in, the end point where SOAP messages from the client reach). We need to do the following:
  1. Describe the interface of our web service
  2. Implement this interface
  3. Launch our web service
  4. Write a client and remotely call the desired web service method
You can launch a web service in different ways: either describe a class with the main method and launch the web service directly as a server, or deploy it to a server like Tomcat or any other. In the second case, we ourselves do not launch a new server and do not open another port on the computer, but simply tell the Tomcat servlet container that “we have written web service classes here, please publish them so that everyone who contacts you can use our use the web service." Regardless of the method of launching the web service, we will have the same client.

Server

Let's launch IDEA and create a new project Create New Project. Let's indicate the name HelloWebService and press the button Next, then button Finish. In a folder src let's create a package ru.javarush.ws. In this package we will create the HelloWebService interface: package ru. javarush. ws; // these are annotations, i.e. a way to mark our classes and methods, // as related to web service technology import javax. jws. WebMethod; import javax. jws. WebService; import javax. jws. soap. SOAPBinding; // we say that our interface will work as a web service@WebService // we say that the web service will be used to call methods@SOAPBinding (style = SOAPBinding. Style. RPC) public interface HelloWebService ( // we say that this method can be called remotely@WebMethod public String getHelloString(String name) ; ) In this code, the WebService and WebMethod classes are so-called annotations and do nothing except mark our interface and its method as a web service. The same applies to the SOAPBinding class. The only difference is that SOAPBinding is an annotation with parameters. In this case, the style parameter is used with a value indicating that the web service will work not through document messages, but as a classic RPC, i.e. to call a method. Let's implement our interface logic and create a HelloWebServiceImpl class in our package. By the way, I note that ending a class with Impl is a convention in Java, according to which the implementation of interfaces is so designated (Impl - from the word implementation, i.e. implementation). This is not a requirement and you are free to name the class whatever you want, but good manners require it: package ru. javarush. ws; // the same annotation as when describing the interface, import javax. jws. WebService; // but here it is used with the endpointInterface parameter, // indicating the full name of the interface class of our web service@WebService(endpointInterface= "ru.javarush.ws.HelloWebService") public class HelloWebServiceImpl implements HelloWebService ( @Override public String getHelloString (String name) ( // just return the greeting return "Hello, " + name + "!" ; ) ) Let's launch our web service as an independent server, i.e. without the participation of any Tomcat and application servers (this is a topic for a separate discussion). To do this, in the project structure in the folder src Let's create a package ru.javarush.endpoint, and in it we will create a HelloWebServicePublisher class with the main method: package ru. javarush. endpoint; // class for running a web server with web services import javax. xml. ws. Endpoint; // class of our web service import ru. javarush. ws. HelloWebServiceImpl; public class HelloWebServicePublisher ( public static void main (String... args) ( // start the web server on port 1986 // and to the address specified in the first argument, // start the web service passed in the second argument Endpoint. publish ( "http://localhost:1986/wss/hello", new HelloWebServiceImpl () ) ; ) ) Now let's run this class by clicking Shift+F10. Nothing will appear in the console, but the server is running. You can verify this by typing the line http://localhost:1986/wss/hello?wsdl in your browser. The page that opens, on the one hand, proves that we have a web server (http://) running on port 1986 on our computer (localhost), and, on the other hand, shows a WSDL description of our web service. If you stop the application, the description will become unavailable, as will the web service itself, so we won’t do this, but move on to writing the client.

Client

In the project folder src Let's create a package ru.javarush.client , and in it the HelloWebServiceClient class with the main method: package ru. javarush. client; // needed to get wsdl description and through it // reach the web service itself import java. net. URL; // this exception will occur when working with a URL object import java. net. MalformedURLException; // classes to parse xml with wsdl description // and reach the service tag in it import javax. xml. namespace. QName; import javax. xml. ws. Service; // interface of our web service (we need more) import ru. javarush. ws. HelloWebService; public class HelloWebServiceClient ( public static void main (String args) throws MalformedURLException ( // create a link to wsdl description URL url = new URL ( "http://localhost:1986/wss/hello?wsdl") ; // We look at the parameters of the next constructor in the very first tag of the WSDL description - definitions // look at the 1st argument in the targetNamespace attribute // look at the 2nd argument in the name attribute QName qname = new QName ("http://ws.site/" , "HelloWebServiceImplService" ) ; // Now we can reach the service tag in the wsdl description, Service service = Service. create (url, qname) ; // and then up to the port tag nested in it, so that // get a link to a web service object remote from us HelloWebService hello = service. getPort(HelloWebService.class); // Hooray! You can now call the remote method System. out. println (hello. getHelloString ( "JavaRush" ) ) ; ) ) I gave maximum comments on the code in the listing. I have nothing to add, so let’s run (Shift+F10). We should see the text in the console: Hello, JavaRush! If you didn’t see it, then you probably forgot to start the web service.

Conclusion

This topic provided a brief excursion into web services. Once again, I will say that much of what I wrote is my guess as to how it works, and therefore you should not trust me too much. I would be grateful if knowledgeable people correct me, because then I will learn something. UPD.

Simple Object Access Protocol (SOAP) is an XML-based protocol that defines the rules for transmitting messages over the Internet between various application systems. It is mainly used for remote procedure calls. SOAP was originally designed to function “above” HTTP (to simplify the integration of SOAP into Web applications), but now other transport protocols, such as SMTP, can also be used.

Let's say you're creating an application access service on the Internet; consumers interact with this service by providing it with information. Your servers process the data and return results to consumers. What is the best way to maintain communication with the system?

You could create a custom client-server application and require consumers to use a custom client program to access your service. But if you are serious about finding yourself in the Internet business, you will have to create a client that runs on all possible client platforms - Windows, Macintosh, Unix, Linux, etc. In other words, you will need to write many different clients.

How do you feel about using the Web? This solution is, of course, quite acceptable, but is tightly tied to the browser implementation, and again you will have to create an infrastructure to send and receive incoming and outgoing information, as well as format and package the data for such exchange. You can choose Java or ActiveX to implement complex applications, but then some users will refuse your services due to clearly inflated bandwidth requirements and inadequate security.

All that is required is a simple protocol that simplifies the packaging of application data and transfers it over the Web using content-adapted XML. By doing so, it ensures that both the sender and the recipient can easily interpret the content of any message. At the same time, thanks to the use of the HTTP Web protocol as a transport, it will be possible to eliminate the need to reduce the level of firewall protection.

The well-described Simple Object Access Protocol (SOAP) is a simple “glue” protocol that allows hosts to remotely invoke application objects and return results. SOAP offers a minimum set of conditions that allow an application to pass messages: the client can send a message to invoke a program object, and the server can return the results of that call.

SOAP is quite simple: messages are XML documents containing SOAP commands. Although SOAP can theoretically be tied to any transport protocol for applications, it is typically used in conjunction with HTTP.

Kennard Scribner, one of the authors of the book Understanding SOAP: The Authoritative Solution(Macmillan USA, 2000), says that SOAP works by converting the information needed to call a method (such as argument values ​​and transaction IDs) into XML format.

The data is encapsulated in HTTP or some other transport protocol and transmitted to the recipient, which is usually the server. This server extracts the SOAP data from the packet, performs the required processing, and returns the results as a SOAP response.

Scribner noted that SOAP acts as a remote procedure call protocol, much like the Remote Method Invocation protocol in Java or the General Inter-ORB Protocol in CORBA.

Because HTTP and XML are used virtually everywhere, SOAP appears to be the most scalable remote procedure call protocol built to date, Scribner said. SOAP is not designed to act as a complete object architecture.

SOAP does not replace the Remote Method Invocation protocol in Java, Distributed Component Object Model, and CORBA; it offers rules that any of these models can use. SOAP is not a complete solution. It does not support object activation or protection. According to Scribner, SOAP developers "trust that users will add this code themselves" by building it on top of SOAP, rather than making it part of the protocol itself.

The figure shows an example taken from the SOAP 1.1 specification in which a host requests a quote service for the price of a particular stock. The SOAP request is embedded in an HTTP POST, and the request body specifies the type of request and the parameter - the stock symbol. The response also provides an XML object encapsulated in the HTTP response with a single return value (34.5 in this case).

Features of SOAP

With SOAP, developers can create Web services as quickly as they can write SOAP messages to call programs for existing applications, and then add those applications to simple Web pages. But in addition, developers have the ability to use SOAP calls in dedicated applications and create applications that can be ported to other people's Web pages, thereby avoiding the time-consuming and expensive development process.

According to Mark Stiver, another author of the book Understanding SOAP, this is precisely the goal Microsoft is pursuing with its promising .Net platform. “This is where SOAP shines. It gives developers a really great way to create applications without having to worry about potential incompatibilities,” he says.

SOAP example

The following example illustrates a SOAP request called GetLastTradePrice, which allows a client to send a request for the latest quotes for a particular stock.

POST/StockQuote HTTP/1.1
Host: stockquoteserver.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction:"Some-URI"

The first five lines (part of the HTTP header) specify the message type (POST), host, payload type, and payload length, and the SOAPAction header specifies the purpose of the SOAP request. The SOAP message itself is an XML document with first a SOAP envelope, then an XML element that specifies the SOAP namespace and attributes, if any. A SOAP envelope can include a header (but not in this case) followed by a SOAP body. In our example, the body contains the GetLastTradePrice request and the symbol of the stock for which the latest quotes are requested. The answer to this query might look like this:

HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn

Again, the first three lines are part of the HTTP header; The SOAP message itself consists of an envelope that contains the response to the original request, labeled GetLastTradePriceResponse, and includes the return value, in our case 34.5.

In general, today there are standard XML data exchange protocols:

  • XML-RPC– you pass the package and indicate which method on the server you want to call.
  • REST- there are some objects on the server. Each object is characterized by some kind of identifier. Each element has its own url. You can do the following with any element: insert, delete, update, select. You simply send the desired request to the server (for example, insert such and such an element). Client-server exchange is based on either JSON or XML.

SOAP (service oriented architecture, a set of loosely coupled services interacting with each other) is based on RPC. The main advantage of RPC is the small number of network resources (entry points) and the many methods involved. Despite this advantage, RPC is an outdated protocol that has a number of disadvantages:

  • The validity of an XML-RPC message cannot be verified. The old protocol was created before schemas (methods of validating data) were standardized in XML. Those. The server accepts requests, it must ensure that the requests are for it and that the data is consistent. In XML-RPC, data types are declared for this, but this is a data type check, and data consistency is not checked (that you received a structure with all the necessary parameters).
  • You cannot create combined messages.
  • You cannot use space and time (appeared after the creation of RPC).
  • You cannot expand the message, i.e. add additional information.

All these shortcomings were solved in XML Schema. This is the industry standard for describing an XML document. Those. it is a way to model arbitrary data. An XML schema can describe a model (relationships between elements and attributes, and their structure), data types (characterizes data types) and a dictionary (names of elements and attributes).

Based on all the shortcomings of XML-RPC, the SOAP protocol was created.

SOAP(Simle Object Access Protocol) - access protocol to an object (to the entry point). Today it is the main industry standard for building distributed applications.

It represents extensions to the XML-RPC language. Those. it is built on the principle: 1 entry point and any methods. The protocol itself in terms of transport (how to transfer data) gives a wide choice: SMTP, FTP, HTTP, MSMQ.

SOAP underlies the implementation of XML web services (XML web services). The disadvantage of SOAP is that it is difficult to learn.

SOAP is based on the exchange of messages between a client and a server (synchronously and asynchronously). Each message carries information about the data (what data is transmitted and received). SOAP describes in advance the entire structure of a message using XML schemas: what should be in the message, how it will be transmitted. This makes it possible, without knowing the server, to understand what is happening there, and allows the server to check whether this message is for it.

XML schema

The purpose of a schema is to describe the structure of the data, i.e. what we have. All data is divided into simple and complex types (scalars and structures). A simple type (string, number, boolean, date) will never contain anything inside. And a structure (object) can contain properties.

Basic SOAP Operations

  • Not just simple client-server information exchange. But also automatic server recognition and search for this server, i.e. the client may not even know anything about the server. Those. the client first searches for the server, finds suitable services, understands what methods are there, what the server has, and calls it.
  • The server publishes its information (location, what methods it supports) so that the client finds this server. Publishing occurs in the UDDI directory.

SOAP message structure:

  • SOAP Envelope - this includes the entire message. Consists of a header and a body.
  • SOAP Header (header) - additional information (authorization, for example).
  • SOAP Body (body) - the message itself.
  • SOAP Fault (error) is a method of transmitting an error from the server to the client.

WSDL

WSDL(Web Services Description Language) - language for describing web services. Used in SOAP. This is a kind of document that describes everything: what namespaces were used, what data schemes were used, what types of messages the server expects from the client, what envelopes belong to what method, what methods exist, what address to send to, etc. Actually, WSDL is a web service. It is enough for the client to study the contents of this document; he already knows everything about the server.

Any server must publish WSDL.

WSDL consists of blocks:

  • Definition of the service itself, i.e. entry point, port is indicated.
  • Methods format. The entry point is linked to operations, i.e. what methods does it support? The type of call and transmission method are indicated. Inside each method there is an explanation of the form in which the data is transmitted - in the form of SOAP.
  • Binding methods to a message.
  • Description of the messages themselves.

Lyrical part.

Imagine that you have implemented or are implementing a certain system that should be accessible from the outside. Those. there is a certain server with which you need to communicate. For example a web server.

This server can perform many actions, work with the database, perform some third-party requests to other servers, do some calculations, etc. live and possibly develop according to the scenario known to him (i.e. according to the developers’ scenario). It is not interesting for a person to communicate with such a server, because he may not be able/want to provide beautiful pages with pictures and other user-friendly content. It is written and works to work and provide data when asked to it, without worrying that it is human-readable, the client will deal with it himself.

Other systems, accessing this server, can already dispose of the data received from this server at their own discretion - process, accumulate, issue to their clients, etc.

Well, one of the options for communicating with such servers is SOAP. SOAP xml message exchange protocol.

Practical part.

A web service (this is the name of what the server provides and what clients use) makes it possible to communicate with the server with clearly structured messages. The fact is that the web service does not accept any data. The web service will respond with an error to any message that does not comply with the rules. The error, by the way, will also be in xml form with a clear structure (which is not true about the text of the message).

WSDL (Web Services Description Language). The rules by which messages are composed for the web service are also described using xml and also have a clear structure. Those. If a web service provides the ability to call a method, it must allow clients to know what parameters are used for this method. If the web service expects a string for Method1 as a parameter and the string should be named Param1, then these rules will be specified in the web service description.

Not only simple types, but also objects and collections of objects can be passed as parameters. The description of an object comes down to a description of each component of the object. If an object consists of several fields, then each field is described, its type, name (what are the possible values). Fields can also be of a complex type, and so on until the description of the types ends with simple ones - string, boolean, number, date... However, some specific types may turn out to be simple, it is important that clients can understand what values ​​they may contain.

For clients, it is enough to know the url of the web service; the wsdl will always be nearby, from which you can get an idea of ​​the methods and their parameters that this web service provides.

What are the advantages of all these bells and whistles:

  • In most systems, the description of methods and types occurs automatically. Those. the programmer on the server just needs to say that this method can be called through a web service, and the wsdl description will be generated automatically.
  • The description, which has a clear structure, is readable by any soap client. Those. no matter what the web service is, the client will understand what data the web service receives. Using this description, the client can build its own internal structure of object classes, the so-called. binding" and. As a result, the programmer using the web service has to write something like (pseudocode):

    NewUser:=TSoapUser.Create("Vasya","Pupkin","admin"); soap.AddUser(NewUser);

  • Automatic validation.

    • xml validation. xml must be well-formed. Invalid xml - immediately an error to the client, let him sort it out.
    • schema-validation. xml must have a certain structure. xml does not match the schema - immediately an error to the client, let him sort it out.
    • Data verification is carried out by the soap server so that data types and restrictions match the description.
  • Authorization and authentication can be implemented using a separate method. natively. or using http authorization.
  • Web services can work both via the soap protocol and via http, that is, through get requests. That is, if the parameters are simple data (without structure), then you can simply call the usual get www.site.com/users.asmx/GetUser?Name=Vasia or post. However, this is not everywhere and not always.
  • ... see on Wikipedia

There are also a lot of disadvantages:

  • Unreasonably large message size. Well, here the very nature of xml is such that the format is redundant, the more tags, the more useless information. Plus soap adds its redundancy. For intranet systems, the issue of traffic is less acute than for the internet, so soap for local networks is more in demand, in particular Sharepoint has a soap web service with which you can communicate with success (and some limitations).
  • Automatically changing the description of a web service can break all clients. Well, it’s like this for any system, if backward compatibility with old methods is not supported, everything will fall off...
  • Not a minus, but a drawback. All method calls must be atomic. For example, when working with a database, we can start a transaction, execute several queries, then rollback or commit. There are no transactions in soap. One request, one answer, the conversation is over.
  • Dealing with the description of what is on the server side (is everything described correctly?) and what is on the client (what was described to me here?) can be quite difficult. There were several times when I had to deal with the client side and convince the server programmer that his data was described incorrectly, but he couldn’t understand anything about it at all, because automatic generation and he shouldn’t, it’s a matter of software. And the error, naturally, was in the method code; the programmer simply did not see it.
  • Practice shows that web service developers are terribly far from the people who use these web services. In response to any request (valid from the outside), an incomprehensible error “Error 5. Everything is bad” may come. It all depends on the conscience of the developers :)
  • I'm sure I still don't remember something...

As an example, there is an open web service belavia:

  • http://86.57.245.235/TimeTable/Service.asmx - entry point, there is also a text description of methods for third-party developers.
  • http://86.57.245.235/TimeTable/Service.asmx?WSDL - wsdl description of methods and types of received and returned data.
  • http://86.57.245.235/TimeTable/Service.asmx?op=GetAirportsList - description of a specific method with an example of the type of xml request and xml response.

You can manually create and send a request like:

POST /TimeTable/Service.asmx HTTP/1.1 Host: 86.57.245.235 Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://webservices.belavia.by/GetAirportsList" ru

the answer will come:

HTTP/1.1 200 OK Date: Mon, 30 Sep 2013 00:06:44 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 4.0.30319 Cache-Control: private, max -age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 2940

PS Previously, the Aeroflot web service was opened, but after 1C added soap support to 8ku, a bunch of 1C beta testers successfully installed it. Now something has changed there (I don’t know the address, you can look it up if you’re interested).
ZZY Disclaimer. He spoke at the everyday level. You can kick.