I've been spending sometime with problem. I have a endpoint I want to send some data and receive a response.
I've look online and I've seen that Zend\Soap\Server is used to build methods, and Zend\Soap\Client can than use those methods. I would like for someone to explain what to write in those methods, and how that helps with getting a response.
$client = new Client($this->wsdl, array('soap_version' => SOAP_1_1));
Now we can $client->SOMEMETHOD();
My questions are: 'Where do I get this method from?', 'what will method do?', and 'how do I use it?'
SOAP short base
SOAP allows to request an online service. (use as a client code) for example you can query AMAZON on a product, know its price, etc.
SOAP works in 2 different ways:
way 1: wdsl mode
when you create a connection to a SOAP client, you must provide a link that will provide an XML file: the wdsl
example: type in your browser:
http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl
congratulation : you see (discover) the way to query AMAZON !
this XML file tells you what you can ask for: a price, a product info, a search, etc ..: these are the routes.
for each route (each possible query) the parameters you must provide, the validity check of these parameters: example: route = search article, param1 = article name, type of parameter = string, etc...
$client = new Client($this->wsdl, array( 'soap_version' => SOAP_1_1 ) )
create a client object :
$this->wsdl a link to xml file (the discovery part)
it's a URI string : example : "http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl"
array( 'soap_version' => SOAP_1_1 ) = i use SOAP version xx, you can add more options in this array.
way 2: non wdsl mode
you do not provide a wsdl link or file...
but you must know how to handle request and responses
deep learning
search on google a tutorial for SOAP,
there are online requester for test purpose, etc...
then use it in zend
I solved my problem, so I'll post it here for anyone to understand.
$client = new Client($wsdl, ['soap_version' => SOAP_1_1]);
$params = [
'args0' => [
'_PRCODASSOC' => null,
'_PRCODDELEG' => null,
'_PRCODFISCALE' => 'BRSLSN312213TY',
'_PRCODFSDDIRI' => null,
'_PRTIPOOPERAWS' => 'REPFAM'
]
];
$client->ws_fam_sgf($params);
$result = $client->getLastResponse();
die($result);
All I did was add 'args' => [] and added all my parameters inside that key.
Related
I am using SOAP::Lite to use a WSDL-defined webservice.
My request (that is working fine) is like that.
<soapenv:Envelope xmlns:soapenv="http://myabc">
<soapenv:Header/>
<soapenv:Body>
<foo>
<p1>max</p1>
<p2>frank</p2>
</foo>
....
My perl code.
my $service = SOAP::Lite->service ("http://mywsdl");
my $ret = $service->foo ("max", "frank");
That is working too.
But I like to name/address my parameters p1 and p2 to have more flexibility.
I tried it with a hash
my %params = (p1 => "max", p2 => "frank");
and also with SOAP::Data.
my #params = (
SOAP::Data->name (p1 => "max"),
SOAP::Data->name (p2 => "frank"));
But it is not working that way.
String value expected instead of SOAP::Data reference
Any ideas how to name my parameters?
EDIT
I like to use wsdl service. So how do I know how the service functions expect their parameters??
Thats the core of my question. I thought about the naming of parameters for a workaround.
If you want to specify the names of the parameters then you should avoid creating a service, which is mostly intended to avoid such housekeeping
If you simply call the method and supply its parameters then it should do what you want
$client->call(foo =>
SOAP::Data->name( p1 => 'max' ),
SOAP::Data->name( p2 => 'frank' )
);
Note that
SOAP::Data->name( p1 => 'max' )
is an undocumented contraction of
SOAP::Data->name('p1')->value('max')
or
SOAP::Data->new( name => 'p1', value => 'max' )
If you would like to use a WSDL file (welcome to hell), you need to use SOAP::WSDL instead of SOAP::Lite. Then you will have an utility called wsdl2perl.pl. If you run it on your wsdl file it will create a lot of perl code, including some classes for each service defined in the wsdl file.
Then in your code you instantiate a new instance of the specific endpoint you want to use, and then you call on this object methods named after the services offered on this endpoint (you do not use the call method anymore), passing a hash reference with all parameters.
You will still need to know what parameters are expected because there is not a lot of introspection available (you can have a workaround that because if you pass an unknown parameter name to the classes they will die and in the error message you will have the list of available parameters, so you can catch that and parse the error string. Ugly, but I did not find another way to do it).
I don't think you can name the parameters if you create the stubs from the service descriptions by calling service().
If you want to assign values to the parameters, there is an example available on CPAN.
Function sayHello
<sayHello xmlns="urn:HelloWorld">
<name xsi:type="xsd:string">Kutter</name>
<givenName xsi:type="xsd:string">Martin</givenName>
</sayHello>
SOAP request
use SOAP::Lite;
my $soap = SOAP::Lite->new( proxy => 'http://localhost:81/soap-wsdl-test/helloworld.pl');
$soap->default_ns('urn:HelloWorld');
my $som = $soap->call('sayHello',
SOAP::Data->name('name')->value('Kutter'),
SOAP::Data->name('givenName')->value('Martin')
);
die $som->faultstring if ($som->fault);
print $som->result, "\n";
You have to replace the value of proxy to http://mywsdl, name and givenName to p1 and p2, sayHello to foo and urn:HelloWorld to your WSDLs namespace.
I also recommend to check this. All the requests can be done without SOAP::Lite.
I have been learning how to program apps using the Mojolicious framework and I am stumped as to why you use route names. For example a route could say
$r->route('/cities/new')
->via('get')
->to(controller => 'cities', action => 'new_form')
->name('cities_new_form');
But what is the purpose of the name parameter? I am new to web frameworks, so maybe this has a trivial answer to it.
Naming the route allows you to reference it later if you want to generate a URL dynamically. With your example, you could do this later in your code:
my $link = $self->url_for( 'cities_new_form' )
and $link would automatically be populated with a URL ending in /cities/new. You can get fancy if your route has dynamic parts. For example:
$r->route( '/cities/:cityname' )
->via( 'get' )
->to( controller => 'cities', action => 'new_form' )
->name( 'cities_new_form' );
Then you can generate a URL like
my $link = $self->url_for( 'cities_new_form', cityname => 'newyork' );
And $link would end up with /cities/newyork.
These are trivial examples, but you can build up fairly complex stuff once your routes get more involved.
If you don't name the route, it gets a default name which is just a concatenation of the alphanumeric characters in it. That can get tedious for long routes so you can use names to abbreviate them.
See also Named Routes in the Mojolicious documentation.
I am creating test cases for my app developed using Mojolicious framework. I am testing the routes for appropriate responses for the REST calls that are made. I use JSON as a means of communication between the server and client. To test GET, POST and DELETE requests I use the following functions
GET : get_ok()POST: post_json_ok() DELETE: delete_ok()
but for PUT I am not able to use put_ok(). And example of my usage of put_ok() would be my $t = Test::Mojo->new;$t->put_ok('this/is/url/to/resource'=>{ "element" => "modified value"})->status_is(204)
I get a bad request status every time(400) and so the test fails. I use Test::Mojo for testing my application.
Additional information:
$t->put_ok('http://localhost:3000/application/instances/system/test'=>{"model" => "testing put"})->status_is(204);
This is the exact test for PUT request that is attempted. model is a property of resource test that is being attempted to be changed to testing put and the expected status response is 204.
The mapping to the controller is done by
$r->route('/application/instances/system/:id, id => qr/[A-Za-z0-9 ]+/ -> via('put')
->to(controller => 'system', action => 'update_sys');
This route calls the update_sys method in the system controller and that is how the resource is located.
Actually, after discussions with SRI on IRC, he pointed me to an example almost identical you your needs in the documentation.
# Test custom transaction
my $tx = $t->ua->build_json_tx('/user/99' => {name => 'sri'});
$tx->req->method('PUT');
$t->tx($t->ua->start($tx))
->status_is(200)
->json_is('/message' => 'User has been replaced.');
So this should work for you!
Postscript:
You might be interested to know that this discussion has brought some progress: the next release of Mojolicious (version 3.66) will now have a cleaner syntax for this purpose, the new request_ok method. The above example can then be rewritten as
my $tx = $t->ua->build_json_tx('/user/99' => {name => 'sri'});
$tx->req->method('PUT');
$t->request_ok($tx)
->status_is(200)
->json_is('/message' => 'User has been replaced.');
Can you share the definition of your route for 'this/is/url/to/resource' ? the server is returning 400, so it appears Mojo::Controller in your app does not understand what you are sending ...
I'm trying to use the vBulletin REST Mobile API to simply register.
The sourced are installed on my local machine and according the documentation https://www.vbulletin.com/forum/content.php/393-User-Registration-Process-Mobile-API
This procedure should not be so hard, especially without humanity and COPPA authentication.
However I've stacked!
The method definition describes "addnewmember" clear, so I've generated a test link, which should do the job.
https://www.vbulletin.com/forum/content.php/365-User-Related-Methods
The link is:
.../forum/api.php?&api_m=register_addmember&api_c=1&api_s=76ec9eec61e7fdfef2f3feee28d5f392&api_sig=8fe54313b333cc0fef4ddd8e398b5c80&api_v=6&agree=1&username=testuser&email=XXXXXX%40gmail.com&emailconfirm=XXXXX%40gmail.com&password=12345678&passwordconfirm=12345678
As a response I get: register_not_agreed
The Docs: register_not_agreed
The agree parameter should be set to 1.
Which is also clear - agree parameter was not there.
Here comes the funny part - In the API-Log I can see that the 'agree' parameter is correctly passed
*1 test_client Gast 13:23, 18.06.2012 register_addmember Array ( [api_m] => register_addmember [api_c] => 1 [api_s] => 76ec9eec61e7fdfef2f3feee28d5f392 [api_sig] => 8fe54313b333cc0fef4ddd8e398b5c80 [api_v] => 6 [agree] => 1 [username] => testuser [email] => ....*
Is there anybody with experience with the Mobile API that could help?
I don't know why it does not work with a pure GET call but I'm sure it will work (because I'm working on a vBulletin API client in Python and I did it this way) if you:
use GET parameters to send api_c, api_sm, api_m, and api_sig
use POST data for all the rest (username, email, agree, etc)
I'm trying to create category with magento soap v2 api call. I'm getting the error:
Attribute "available_sort_by" is required.
Code for calling the Api:
$category_data = array( "name" => "testcategory", "is_active" => "1", "include_in_menu" => "1","available_sort_by" => "","default_sort_by" => "");
$result = $client->catalogCategoryCreate($session,2,$category_data,1);
echo $result;
I have tried also with "available_sort_by" => array("name", "price", ...)
Is this the right way for calling the v2 soap api.
Thanks for any advice.
The WSDL does define what data you need for your call and exposes it for you to look at if you put 'trace' on your API SOAP calls.
After your call, with trace on, you can get your last XML, but it will be tidied up by the SOAP to be shoehorned into what the WSDL thinks you need for that call. The data will be different to what you submitted and show fields you never knew were in existence - it kind of reveals the documentation that you wish you had to start with.