How to pass response values to Java API from Karate - web-services

How can I pass values from Karate API to Java class?
As mentioned in the documentation, I used the following code snippet to get the response from Java API. But its returning the response with un-formatted JSON content.
Map<String, Object> result = CucumberRunner.runClasspathFeature("demo/java/from-java.feature", args, true);
And then, I used the following script to print the response.
for(Map.Entry<String , Object> entry: getMbrWksMembershipDetailsResponse.entrySet())
{
if (entry.getKey().equalsIgnoreCase("response"))
{
System.out.println(entry.getValue());
}
}
It shows like,
{soap:Envelope={_={soap:Body={ns1:getMbrWksMembershipDetailsResponse={_={ns4:WksMembershipSummaryResponse={_={ns2:customerSummary={ns2:address={ns2:city=SOUTH CHESTERFIELD, ns2:country=USA, ns2:isoCountryCode=US, ns2:line1=9998, N. MICHIGAN ROAD., ns2:postalCode=23834, ns2:state=VA}, ns2:allowPasswordChange=true, ns2:arpMember=false, ns2:brandCode=RCI, ns2:brandId=1, ns2:companyCode=RCI, ns2:eliteMemberRewardStatus=false, ns2:eliteRewardStatus=true, ns2:europePointsClubMember=false, ns2:firstName=FRANK, ns2:homePhone=804/733-3004, ns2:isoCurrencyCode=USD, ns2:isoLanguageCode=EN, ns2:language=EN, ns2:lastName=BROWNING B, ns2:locale=en_US, ns2:memberDeveloperRenewed=false, ns2:memberEnrolledDate=2009-10-26T00:00:00-04:00, ns2:memberEnrolledForDirectDebit=false, ns2:memberEnrolledForPltDirectDebit=false, ns2:memberStatus=A, ns2:middleName=B, ns2:msgTranslationLanguageCode=EN, ns2:officePhone=0/-0, ns2:pointsCurrencyCode=0......
So it's little difficult to split the data based on the fields / tags from Map.
Please suggest what is the best option to get the values field wize / tag wise from Java API.
Thanks.

Yes, XML is internally held as a strange Map structure, refer to the section on type-conversion to understand more.
You have a simple way to do this. Just define a new variable that is the response converted to a string.
* xmlstring responseXml = response
After this you just need to get the responseXml out of the Map returned by the Java API which will be a string.
Note: don't use the Java API unless you are really trying to mix Karate with something else. The whole point of Karate is to avoid using Java for testing JSON and XML web-services.

Related

Unable to call object from a List located in external BeanShell script [Jmeter]

My end goal here is to get a string from a list that is created dynamically from a JSON response. I am having troubles calling a value from the list that is created in an external BeanShell script. The external script reads the JSON response and creates the list from the filtered response.
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Filter;
try{
String json = new String(prev.getResponseDataAsString());
List allPositiveAffects = JsonPath.read(json, "$.affectTags[?(#.value > 0.0)].key", new Filter[]{});
vars.putObject("allPositiveAffects",allPositiveAffects);
log.info("allPositiveAffects: " + allPositiveAffects);
int positiveAffectCount = allPositiveAffects.size();
vars.put("positiveAffectCount",Integer.toString(positiveAffectCount));
} catch (Throwable ex){
log.error("Error:\n", ex);
}
allPositiveAffects returns the expected values, so now I want to get one of those values into a subsequent JSON POST.
My Jmeter test setup:
- Thread Group
+ JSON GET request
- BeanShell PostProcessor
+ JSON POST request
Attempting to get a value from allPositiveAffects has proven to be not as easy as calling allPositiveAffects.get(n) like I can within my BeanShell script.
I haven't figured out an easy way to get the contents of the Lists. Am I missing something? I have tried several different things in my JSON POST request. The latest being:
//json POST data
{
"entries":[
"id": -1,
"key": "${__BeanShell(${allPositiveAffects}.get(1))}"]
}
Which returns the following error:
java.lang.ClassCastException: net.minidev.json.JSONArray cannot be cast to java.lang.String
Any help on a solution or workaround for this would be greatly appreciated. It would be a lot easier for me to be able to call a List instead of creating various variables.
I believe that you could just add .toString() to your expression like:
`${__BeanShell(${allPositiveAffects}.get(1).toString())}`
By the way, Beanshell has some performance overhead so I would rather suggest going for JSON Path Extractor which is available via Extras with Libs Set of JMeter Plugins package, it should be more convenient and less resource consuming.
See Using the XPath Extractor in JMeter (scroll down to "Parsing JSON") for installation instructions and some JSON Path language reference examples.

CAML query in getLIstItems method returns no rows of items

I am invoking Sharepoint's List Web services and using the getListItems() method. In particular, I am keen on specifying a CAML query because I really want it to just retrieve one item that I am specifically interested in. This I am doing by specifying a query in my XML string, in varying degrees of combinations, either by specifying the EncodedAbsUrl, the LinkFileName, the URL or the FileRef, with most results returning 0.
The XML query looks like this :
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body><GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/"><listName>{5cbc4407-3851-4e00-964a-bb7e9b430f9f}</listName> <viewName></viewName> <rowLimit>1000</rowLimit> <webID></webID>
**<query><Query><Where><Eq><FieldRef Name = "FileRef"/><Value Type = "Text">"/Shared%20Documents/Ashish/Word_feb27.doc"</Value></Eq></Where></Query></query>**
<viewFields><ViewFields><FieldRef Name="FSObjType"/><FieldRef Name="LinkFilename"/><FieldRef Name="UniqueId"/><FieldRef Name="FileRef"/><FieldRef Name="FileRef"/><FieldRef Name="EncodedAbsUrl"/><FieldRef Name="FileSizeDisplay"/><FieldRef Name="_UIVersionString"/><FieldRef Name="_owshiddenversion"/></ViewFields></viewFields></GetListItems> </S:Body></S:Envelope>
Without the tags this Soap request does infact work, and it retrieves all the items that area available in the List. The frustration begins when i specify the query tag. In particular the Following combinations have been attempted by me
FieldRef.name = {LinkFileName, EncodedAbsUrl, URL,FileRef} and Value.type = {Text, URL}
Either they yield results with no 0 fields in it or they return internal errors. I figure, this is a syntactical issue and would rather shoot this question to you guys who have probably dunnit in the past to see where I am possibly messing it up.
Thanks
I would recommend using CAML Query Builder and Fiddler. Query builder can connect SP using Web services and you can build the query with that. After you got your expected results, capture the Web service request with Fiddler and use it :)
BTW: Have you considered using Sharepoint Client Object model? You do not have to worry about SOAP messages.
Remove the <query><Query> tags.

REST service returning "useful" information for demos

I am looking for a REST service that I could use in demo code. I'd like the service:
To take at least one parameter (as a request parameter, or XML POSTed as the body of the HTTP request).
To return the result as XML (not JSON).
To be accessible anonymously (I'll call the service in sample code, so I don't want to put my key in the code, or request users to get a key).
When the Twitter API supported XML (not just JSON), I was typically using their search API. But really anything mainstream enough, easy enough to understand will do (information about zip code, weather for a city…).
If you are using .Net, why don't you just create a tiny MVC application that has a controller that exposes a method that returns some sort of formatted XML? That way you can run the whole thing locally.
EDIT:
You know, I think you can use Google Maps API without a key. I created a test project a couple of days ago. Here is a .Net code snippet (only included so that you can see how I am calling the service):
private static string GetString(Uri requestUri)
{
var output = string.Empty;
var response = WebRequest.Create(requestUri).GetResponse();
var stream = response.GetResponseStream();
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
output = reader.ReadToEnd();
reader.Close();
}
}
response.Close();
return output;
}
I pass in a uri with a url:
https://maps.googleapis.com/maps/api/directions/xml?mode=walking&origin={0},{1}&destination={2},{3}&sensor=false
Where {0},{1} are the first lat/long, and {2},{3} are the second. I am not attaching a key to this and it worked for testing. My method returns a string that later I handle like so:
var response = XDocument.Parse(GetString(request));
which gives me back xml. Again, I still recommend just creating your own web app and then deploying it somewhere publicly accessible (either in a LAN or on the web), but if you just need a web service to return XML you can use that.
The Yahoo! Weather API can be used for this. It takes a location as a request parameter and returns the weather forecast for that location as XML. It also returns weather information as HTML, which you could display as-is to the user. You can see an example of this below. Also make sure that you respect the term of use described at the bottom of the Weather API documentation page.

How do i create a REST service that accepts a List of objects from a client and how do i create the client.

i am trying to create a REST service that accepts a List of objects from a client and gives back a zip file.
i understand how to give back the zip file alright.
But i am right now trying to figure out a way i can pass a List of objects from a REST client/browser to the Rest service and how do i accept the List in the REST service.
Should this be done via XML input ?
or maybe the #consumes annotation could help?
Much thanks .
Som
You need to think out more clearly what you wish to do. There's no really good reason for taking a list of objects and returning a ZIP of them; you might as well use a local zip program (which just about all computers already have). That indicates that we instead need to be looking at something sensible: for example, a list of names of objects that you'll return a ZIP of, that makes a lot of sense. There are other sensible things you could be doing too, but you have to work it out in your mind what you want to happen.
Because you mention “#consumes annotation”, I'm going to assume you're using JAX-RS (i.e., Java). That's nice, because it's entirely possible to do on-the-fly ZIP generation with that; the content type you want to produce is application/zip. The easiest way I've found to handle the specification of the list of descriptions of things to return is as a wrapped list, where you use something like JAXB to do the mapping (which gives you XML support; some frameworks also support JSON off the same data models). To do a wrapped list, you use something like this:
#XmlRootElement
public class Wrapper {
#XmlElement
public List<String> item;
}
That then produces/handles XML documents like this (a three item list):
<wrapper>
<item>foo</item>
<item>...</item>
<item>bar</item>
</wrapper>
You'll need to set up the #Consumes annotation so that the content type accepted is application/xml (at least), and also consider what type of operation is involved and on what resource.
[EDIT]: In order to create a REST service that takes a list of strings as arguments, the easiest method is indeed to use a wrapper object, much as above. (You can't take a raw list; it needs to be a well-formed XML document when it's on the wire.) We then set up the annotated service method like this:
#POST
#Path("somewhere/{id}")
#Consumes("application/xml")
#Produces("application/zip")
public Response getSomeBytesForList(#PathParam("id") String id, Wrapper req) {
List<String> items = req.item; // For example...
byte[] zip = generateZipBytes(id, items); // or however
return Response.ok(zip).type("application/zip").build();
}
The key is that the req argument (the name is arbitrary, of course) is the only argument that is not annotated, that it is of a type that is JAXB-enabled, and there is an overall #Consumes ("application/xml") annotation to enable the JAXB processing of the request body. (I handle the returning of a ZIP by generating the Response directly rather than relying on the framework to do the processing for me; this lets me control the content type handling a little more precisely.)
Also note that some frameworks can also transfer JAXB-annotated objects as JSON documents, just by having a bit of extra annotation; you just state that the method can accept both "application/xml" and "application/json" in the #Consumes annotation. I do not know whether this applies to the framework you are using (I've only tested it with Apache CXF).

Forcing ASP.net webservice to return JSON

I have an ASP.net web service that I'm using for a web application which returns a either XML or JSON data to me, depending on the function I call. This has been working well thus far, but I've run into a problem. I want to create an "export" link on my page that will download a JSON file. The link is formatted very simply:
Export This Item
As you might imagine, this should export item 2. So far so good, yes?
Problem is that since I'm not specifically requesting that the accepted content type is JSON, ASP.net absolutely refuses to send back anything but XML, which just isn't appropriate for this situation. The code is essentially as follows:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public Item ExportItem(int itemId)
{
Context.Response.AddHeader("content-disposition", "attachment; filename=export.json"); //Makes it a download
return GetExportItem(itemId);
}
Despite my specifying the ResponseFormat as JSON, I always get back XML unless I request this method via AJAX (using Google Web Toolkit, BTW):
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, "mywebserviceaddress/ExportFunc");
builder.setHeader("Content-type","application/json; charset=utf-8");
builder.setHeader("Accepts","application/json");
builder.sendRequest("{\"itemId\":2}", new RequestCallback(){...});
That's great, but AJAX won't give me a download dialog. Is there any way to force ASP.net to give me back JSON, regardless of how the data is requested? It would seem to me that not having a manual override for this behavior is a gross design oversight.
QUICK ANSWER:
First off, let me say that I think that womp's answer is probably the better way to go long term (Convert to WCF), but deostroll led me to the answer that I'll be using for the immediate future. Also, it should be noted that this seems to work primarily because I wanted just a download, may not work as well in all situations. In any case, here's the code that I ended up using to get the result I wanted:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ExportItem(int itemId)
{
Item item = GetExportItem(itemId);
JavaScriptSerializer js = new JavaScriptSerializer();
string str = js.Serialize(item);
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.AddHeader("content-disposition", "attachment; filename=export.json");
Context.Response.AddHeader("content-length", str.Length.ToString());
Context.Response.Flush();
Context.Response.Write(str);
}
Please note the return type of void (which means that your WDSL will be next to useless for this function). Returning anything will screw up the response that is being hand-built.
Asp.net web services are SOAP-based web services. They'll always return XML. The Ajax libraries came along and the ScriptMethod stuff was introduced, but it doesn't change the underlying concept of it.
There's a couple things you can do.
WebMethods are borderline obsolete with the introduction of WCF. You might consider migrating your web services to WCF, in which you'll have much greater control over the output format.
If you don't want to do that, you can manually serialize the result of your webservice calls into JSON, and the service will wrap that in a SOAP header. You would then need to strip out the SOAP stuff.
Here are two forums threads for your reference:
http://forums.asp.net/t/1118828.aspx
http://forums.asp.net/p/1054378/2338982.aspx#2338982
I have no clear idea. They say on concentrating on setting the content type to application/json. I haven't worked with wcf before, but I think you can make use of the Response object.
Set the content type on the response object. Do a response.write passing your json data as string and then do a response.end.
Just thought I'd throw this out there since it wasn't mentioned previously... if you use WebServices with ASP.NET 3.5, JSON is the default return format. It also comes along with JSON serializer so you can stop using the JavascriptSerializer.
This article on Rick Strahl's blog talks about the strongly-typed conversion you can do between server side classes and JSON objects from the client.
I've recently completed a project using this new JSON stuff in .NET 3.5, and I'm extremely impressed with the performance. Maybe it's worth a look...