How do I invoke a MobileFirst Platform Adapter using PUT? - ibm-mobilefirst

This is similar to the question asked here, but that question was not exactly answered to what the problem is.
Customer.xml
<?xml version="1.0" encoding="UTF-8"?>
<wl:adapter name="Customer"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wl="http://www.ibm.com/mfp/integration"
xmlns:http="http://www.ibm.com/mfp/integration/http">
<displayName>Customer</displayName>
<description>Customer</description>
<connectivity>
<connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
<protocol>https</protocol>
<domain>kenatibm.cloudant.com</domain>
<port>443</port>
</connectionPolicy>
</connectivity>
<procedure name="addCustomer"> </procedure>
</wl:adapter>
Customer-impl.js
function addCustomer(param1) {
var input = {
method : 'PUT',
returnedContentType : 'json',
path : 'userInputRequired',
body : {
contentType: 'application/json',
content : param1
}
};
return WL.Server.invokeHttp(input);
}
The issue is that even though I have defined the method as a PUT, when testing using File Run As | Call MobileFirst Adapter the user interface only displays a GET method, there is no option for PUT.
So is the answer that the GET will actually do a PUT or is this a bug or is there a configuration parameter that I am missing?

I think you are confusing how you invoke/test the adapter, with what verb it uses on the back-end system it is calling. You are testing/invoking it using GET, but the adapter is then calling your backend system - http://kenatibm.cloudant.com/backendsystem - using PUT.
This is broadly the same explanation as Dave gave in your previous question.

In short, the answer is that the GET will actually do a PUT.
Parameters are passed to the adapter in a GET request and then the adapter constructs a PUT request to perform the actual procedure. In your code, you can see how the 'param1' is passed by the wizard to the function and then it is set to as the 'content' of the PUT request. It's definitely a little confusing.

Related

How to send a XML API request in cypress (SOAP API)

I need to send XML requests in cypress but I don't know how to do that. Generally, I worked with cy.request with rest API's. Is it possible to send XML requests in cypress?
How can I do that? Any help would be great!! An example would be lovely!
I left an example request that I use in postman without a problem. But to automate my test I need to send that request in cypress.
(POST request)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<MT_ServiceOrderInitiaionandMgmt xmlns:prx="***"
xmlns="***">
<VKONTO>***</VKONTO>
<NAME>***</NAME>
<PORTION>***</PORTION>
<AKLASSE/>
<DATUM>***</DATUM>
<Contact>
<RELTYP/>
<NAME>***</NAME>
<TEL_NUMBER>***</TEL_NUMBER>
<PHTYPE>***</PHTYPE>
<SMTP_ADDR>***</SMTP_ADDR>
</Contact>
<LifeSupportIndicator/>
<QMNUM>***</QMNUM>
<QMART>***</QMART>
<MNCOD>***</MNCOD>
<QMTXT>***</QMTXT>
<NOTST>***</NOTST>
<ServiceAddress>
<STREET>***</STREET>
<CITY1>***</CITY1>
<REGIO>***</REGIO>
<LOCATION>***</LOCATION>
<POST_CODE1>***</POST_CODE1>
<HAUS_NUM2/>
</ServiceAddress>
<ABLEINH>***</ABLEINH>
<CO_ASTTX>***</CO_ASTTX>
<STRMN/>
<STRUR>***</STRUR>
<LTRMN/>
<LTRUR>***</LTRUR>
<ERDAT>***</ERDAT>
<MZEIT>***</MZEIT>
<ERNAM>***</ERNAM>
<AEDAT/>
<AEZEIT>***</AEZEIT>
<AENAM/>
<PPSID>***</PPSID>
<ExternalReference>
<ID></ID>
<SYSNAME>***</SYSNAME>
<TYPE>***</TYPE>
</ExternalReference>
<REFNUM/>
<PRIOK/>
<LONT_TXT>***</LONT_TXT>
<PREMS>***</PREMS>
<Meters>
<TPLNR>***</TPLNR>
<VBSARTTEXT>***</VBSARTTEXT>
<TERMSCHL/>
<DLNOT>***</DLNOT>
<STORT>***</STORT>
<KTEXT>***</KTEXT>
<EINBDAT>***</EINBDAT>
<ISPRIM>***</ISPRIM>
<SERNR>***</SERNR>
<MET_SERNR></MET_SERNR>
<HERST>***</HERST>
<TYPBZ/>
<PREISKLA>***</PREISKLA>
<EQKTX>***</EQKTX>
<DSTAT>***</DSTAT>
<MEINS>***</MEINS>
<STANZVORE>***</STANZVORE>
<ISTABLART>***</ISTABLART>
<V_ZWSTAND></V_ZWSTAND>
<E_ZWSTANDO>***</E_ZWSTANDO>
<E_ZWSTANDU>***</E_ZWSTANDU>
<E_VERBERW>***</E_VERBERW>
<ADAT>***</ADAT>
<ATIM>***</ATIM>
<MTU_TPLNR/>
<MTUSN>***</MTUSN> >
<MTU_EQKTX/>
<MTU_EINBDAT>***11</MTU_EINBDAT>
<MTU_SERNR></MTU_SERNR>
<PORT>***</PORT>
</Meters>
</MT_ServiceOrderInitiaionandMgmt>
</soap:Body>
</soap:Envelope>
there are no big differences between standard rest API requests and XML Soap API requests.
cy.request({
method: "POST",
url: "Request URL",
headers: {
"Content-Type": "text/xml;charset=UTF-8",
authorization: "Bearer " + "auth token",
SOAPAction: "serviceOrder",
},
//you have to write your XML body here as a string. I leave a small part
//of my API's body to be an example if someone needs it in the future.
body: '<?xml version="1.0" encoding="UTF-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><MT_ServiceOrderInitiaionandMgmt xmlns:prx="***" xmlns="***"><VKONTO>5883000</VKONTO><NAME>cypress</NAME><PORTION>MBC87<MTU_EINBDAT>2002-05-11</MTU_EINBDAT><MTU_SERNR></MTU_SERNR><PORT>1</PORT></Meters></MT_ServiceOrderInitiaionandMgmt></soap:Body></soap:Envelope>',
})
.then((res) => {
//Do something with the response.
});

Slideshare api getting 'Failed API Validation' error response

I have applied for slideshare API and i got the API and the secret. All i have did is a simple GET request to slideshare which gives me results with the help of a tag.
This is my deluge script which i have tried to call the url using the API.
As per the documentation, i have got the unix time stamp and SHA1 hash.
param = Map();
param.put("api_key","XYZ");
param.put("ts","1565085930");
param.put("hash","xxxxxxxxxxxxxxxxxxxxxxxxx");
param.put("tag","cricket");
request = invokeurl
[
url :"https://www.slideshare.net/api/2/get_slideshows_by_tag"
type : GET
parameters: param
];
info request;
This is the response error i get:
<?xml version="1.0" encoding="UTF-8"?>
<SlideShareServiceError>
<Message ID="1">Failed API validation</Message>
</SlideShareServiceError>
Thank you.
Looks like the API does not work with a GET request. Try the same using a POST request and it should work. The same failed with POSTMAN and it worked only after the request type was changed to POST.
param = Map();
head = Map();
param.put("api_key","XXXXXXXX");
param.put("ts",1577955246);
param.put("hash","b3f3f803XXXXXXXXXXXXXXXX8be21d");
param.put("tag","cricket");
request = invokeurl
[
url :"https://www.slideshare.net/api/2/get_slideshows_by_tag"
type : POST
parameters: param
];
info request;
Response:
<?xml version="1.0" encoding="UTF-8"?>
<Tag>
<Name>cricket</Name>
<Count>0</Count>
</Tag>

Unable to Edit/Create playlists in "playlists" container in Sonos version 5.4 (latest update)

When I updated to version 5.4 I no longer have the option to create a playlist in the "playlists" container, nor to add a track to a playlist already existing in it. In version 5.3 it was working well. I also checked other Music Services on Sonos, same problem. Did anything change in the specifications for User Content Playlists that is not specified in the documentation for Playlist Editing?
This is how I'm adding my User Content container:
$result->mediaCollection[] = array('id'=>'playlists', 'title'=>'My Playlists', 'itemType'=>'favorites', 'containsFavorite'=>true, 'displayType'=>'genreList', 'readOnly'=>false, 'userContent'=>true, 'renameable'=>true, 'albumArtURI'=>PATH.'/img.png');
Edit:
I am using the Android controller (version 5.4, build 29590261) and I am testing on a Play:1 (version 5.4, build 29591030).
I am able to add a song/playlist to an already existing playlist or to a new playlist (by long press on a song to get to the extended metadata, and then "Add Track to 'Service Name' Playlist"), but what I can't figure out how to do is: deleting a playlist, renaming a playlist, and editing songs in a playlist (reorder, delete songs). I don't have a screenshot for version 5.3 but there was an button in the top right corner (three vertical dots) of the playlists container from which one can edit playlists or create new ones (check the screenshots below, from version 5.4). Am I missing something?
Edit 2:
I figured out what is causing the issue. I am using the .wsdl for beta in order to be able to implement Custom Item Display (This is not beta anymore, as I understood from the Adding New SMAPI Features page). When I revert to the normal Sonos.wsdl file from the Sonos Documentation, the info and options button appears again. How can I use Custom Item Display while keeping the info and options button there and all functionalities of playlist editing unchanged?
Note: the Sonos(beta).wsdl was here but it's not available anymore.
Edit 3:
I downloaded the Sonos.wsdl from the Sonos documentation, but I still can't see the button. In order to reproduce the issue, please check the following PHP implementation and Presentation Map XML code:
PHP implementation:
define('BASE_PATH', rtrim("http://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']), '/'));
class SonosAPI
{
public function getMetadata($args)
{
$result = new StdClass();
$result->index = $args->index;
switch($args->id) {
case 'root':
$result->mediaCollection[] = array('id'=>'playlists', 'title'=>'My Playlists', 'itemType'=>'favorites', 'displayType'=>'genreList', 'readOnly'=>false, 'userContent'=>true, 'renameable'=>true, 'albumArtURI'=>BASE_PATH.'/image.png');
$result->count = $result->total = 1;
break;
case 'playlists':
$result->mediaCollection[] = array('id'=>'123', 'title'=>'Title', 'itemType'=>'playlist', 'displayType'=>'genreList', 'canPlay'=>true, 'readOnly'=>false, 'userContent'=>false, 'renameable'=>true, 'albumArtURI'=>BASE_PATH.'/image.png');
$result->count = $result->total = 1;
break;
}
return array('getMetadataResult' => $result);
}
}
$server = new SoapServer("Sonos.wsdl", array('cache_wsdl' => 0)); // disable cache in development
$server->setClass('SonosAPI');
try {
$server->handle();
} catch (Exception $e) {
Log("[ERROR] ".$e->getMessage());
}
?>
Presentation Map file:
<?xml version="1.0" encoding="utf-8" ?>
<Presentation>
<PresentationMap type="DisplayType">
<DisplayType id="genreGrid">
<DisplayMode>GRID</DisplayMode>
</DisplayType>
<DisplayType id="genreList">
<DisplayMode>LIST</DisplayMode>
</DisplayType>
<DisplayType id="genreHero">
<DisplayMode>HERO</DisplayMode>
</DisplayType>
<DisplayType id="genreEditorial">
<DisplayMode>EDITORIAL</DisplayMode>
</DisplayType>
<DisplayType id="twoLine">
<Lines>
<Line token="title"/>
<Line token="summary"/>
</Lines>
</DisplayType>
</PresentationMap>
</Presentation>
XML response to getMetadata of root (which contains the playlists container):
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns1="http://www.sonos.com/Services/1.1" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns1:getMetadataResponse>
<ns1:getMetadataResult>
<ns1:index>0</ns1:index>
<ns1:count>4</ns1:count>
<ns1:total>4</ns1:total>
<ns1:mediaCollection>
<ns1:id>rootlang:ar</ns1:id>
<ns1:itemType>collection</ns1:itemType>
<ns1:displayType>genreGrid</ns1:displayType>
<ns1:title>Arabic</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
<ns1:mediaCollection>
<ns1:id>rootlang:en</ns1:id>
<ns1:itemType>collection</ns1:itemType>
<ns1:displayType>genreGrid</ns1:displayType>
<ns1:title>International</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
<ns1:mediaCollection>
<ns1:id>rootlang:default</ns1:id>
<ns1:itemType>collection</ns1:itemType>
<ns1:displayType>genreGrid</ns1:displayType>
<ns1:title>Arabic + International</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
<ns1:mediaCollection renameable="true" readOnly="false" userContent="true">
<ns1:id>playlists</ns1:id>
<ns1:itemType>favorites</ns1:itemType>
<ns1:displayType>genreList</ns1:displayType>
<ns1:title>My Playlists</ns1:title>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
</ns1:getMetadataResult>
</ns1:getMetadataResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
XML response to getMetadata of playlists:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns1="http://www.sonos.com/Services/1.1" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<ns1:getMetadataResponse>
<ns1:getMetadataResult>
<ns1:index>0</ns1:index>
<ns1:count>1</ns1:count>
<ns1:total>1</ns1:total>
<ns1:mediaCollection renameable="true" readOnly="false" userContent="false">
<ns1:id>playlist:19663408</ns1:id>
<ns1:itemType>playlist</ns1:itemType>
<ns1:displayType>genreList</ns1:displayType>
<ns1:title>Test Playlist</ns1:title>
<ns1:canPlay>true</ns1:canPlay>
<ns1:albumArtURI>{SOME LINK}</ns1:albumArtURI>
</ns1:mediaCollection>
</ns1:getMetadataResult>
</ns1:getMetadataResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Custom Display Types were made available in the most recent production software update. The beta wsdl that you were using is for v5.4 which is now the current production build. Make sure that you are using the production version of the wsdl and you will have info & options and also have access to Custom Display Types (provided they are properly enabled in your service).
However I have confirmed that we do have a bug when using Display Types with playlist containers when playlist editing is enabled. The work around is to removed the displayType node from your root playlist and child playlist containers (all other containers that use displayType do not need to be changed). This work around has been tested and works. We have opened an issue to track this internally.

dojo/request/xhr returning xml instead of json

I'm using a simple dojo xhr request:
require(["dojo/query", "dojo/on", "dojo/dom-style", "dojo/request/xhr", "dojo/domReady!"],
function (query, on, domStyle, xhr) {
xhr("api/products", {
handleAs: 'json'
}).then(function (data) {
console.log('GOT DATA FROM DOJO XHR', data);
}, function (err) {
console.log('ERROR FROM DOJO XHR', err);
});
}
);
This works fine, but the data returned is as XML not JSON.
However, the same call in jQuery returns the data in JSON.
When I look at the headers, for the jQuery call it shows: Content-Type application/json; charset=utf-8, but for the dojo call it shows: Content-Type application/xml; charset=utf-8
I also added:
headers: { "Content-Type": "application/json; charset=uft-8" }
to the xhr parameters, but still no luck, it still returns xml.
What gives? How do you tell dojo xhr to handle it as json? I'm using dojo 1.8.3.
the server doesnt behvae like that by itself. check using firebug what dojo and jquery are requesting when they do a xhr. there has to be a param that tells the server that it is dojo or jquery. change that parameter.
dojo and jquery are the same, they are based on js and they both use xhr. please consider posting the exact request information for both.
Fixing server side works, but this is a band-aid solution. Server responds correctly to what it sees in the Accept header. Even if in Dojo xhr call you specify 'application/json', for some reason Firefox replaces it with 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8' or something similar. As a result .NET sends back XML instead of JSON. Does not happen in other browsers.
I am still looking at how to fix it in a correct way.
Update: I think I have an answer, but not sure why it fixes it. If I set headers value in xhr request like the following, then everything works in Firefox:
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json'
}
If I use double-quotes, then these headers are not transmitted to the server and XML is returned instead.
Ok, found the problem of why it's happening, but not the root cause.
I'm using the web api with asp.net mvc4 for the json service. It turns out somehow that for dojo the service is returning xml but for jQuery it returns json.
So, if it interests anyone else, how I fixed it, is that in WebApiConfig I removed xml as a supported return type:
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
Since I"m only interested in JSON, this is ok for me, but if you need to support both, then you may have to look deeper.
So, to summarize, the issue is not really a dojo xhr issue, i.e, not a client issue, it's a server issue not handling the request properly.
Hope it helps anybody else.

Perform authentication to Polarion webservice with Savon

I am attempting to follow the discussion here using Ruby and Savon. I am able to retrieve a session ID, but whenever I perform a request from the clients that require authentication (tracker), I receive an Authorization Failed error.
require 'Savon'
tracker_url = 'http://myserver/polarion/ws/services/TrackerWebService?wsdl'
session_url = 'http://myserver/polarion/ws/services/SessionWebService?wsdl'
# todo handle bad login credentials gracefully
session_client = Savon.client(wsdl: session_url)
response = session_client.call(:log_in, message: {user_name: 'lsimons', password: 'mypassword'})
session_id = response.header[:session_id]
puts "Session ID: #{session_id}"
tracker_client = Savon.client(wsdl: tracker_url, soap_header: {"session" => session_id}, headers: {"sessionID" => session_id})
puts "Requesting Workitem"
begin
tracker_client.call(:get_work_item_by_id, message: {project_id: 'myProject', workitem_id: 'myWorkitem'})
rescue
puts "Client call failed"
end
This code creates the following SOAP request for the tracker_client:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ins0="http://ws.polarion.com/TrackerWebService-impl" xmlns:ins1="http://ws.polarion.com/types" xmlns:ins2="http://ws.polarion.com/TrackerWebService-types" xmlns:ins3="http://ws.polarion.com/ProjectWebService-types" xmlns:tns1="http://ws.polarion.com/TrackerWebService" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header>
<session>2164640482421325916</session>
</env:Header>
<env:Body>
<tns1:getWorkItemById>
<ins0:projectId>myProject</ins0:projectId>
<ins0:workitemId>myWorkitem</ins0:workitemId>
</tns1:getWorkItemById>
</env:Body>
</env:Envelope>
However, in the forum discussion, the sessionID element occurs before the header. I didn't think this was possible with standard SOAP? Is there a way to achieve this with Savon or am I misinterpreting the forum discussion?
I faced the same problem following the same thread. This is how I made it work (by replicating the response headers of the log_in request):
tracker_client = Savon.client(
wsdl: tracker_url,
soap_header: {
"ns1:sessionID" => session_id,
:attributes! => {
"ns1:sessionID" => {
"env:actor" => "http://schemas.xmlsoap.org/soap/actor/next",
"env:mustUnderstand" => "0",
"xmlns:ns1" => "http://ws.polarion.com/session"
}
}
}
)
Old question but thought I can add some info to hopefully help somebody.
I am using lolsoap to talk to polarion. In the above resulting document, the sessionID element is wiped off any namespaces and attributes. Also the assessment is right that actor and mustUnderstand attributes seem irrelevant.
To add header properly though with all fluff, one needs to get the Nokogiri::XML::Node and dup it, then add it to the header of the doc. This is a bug in nokogiri/libxml2 that adding child elements can often break namespaces unless Node is cloned before adding [1].
In lolsoap it is done something like:
auth_header = login_response.nokogiri_doc.xpath("//*[local-name()='sessionID']")[0].dup
other_request.header.__node__ << auth_header
Please note the dup operation. header.__node__ is just the header Nokogiri::XML::Element of a random SOAP request.
The dup operation makes adding desired element into another one with all necessary namespaces and attributes properly defined.
I don't know if savon allows one to directly touch request XML but I guess it does. Thus HTH
[1] https://github.com/sparklemotion/nokogiri/issues/1200