How to download CSV using REST API? - export-to-csv

Here's a REST API that I am trying for downloading data as CSV file.
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var data = '\n'; // workaround to separate <xml> start tag on first line
data += 'Firstname,Lastname,Username' + '\n';
data += 'Nikhil,vartak,niksofteng' + '\n';
data += 'Unknown,person,anonymous' + '\n';
response.setHeader("Content-Disposition", "attachment;filename=Xyz.csv");
response.setContentType("text/csv");
response.setBody({'data':data});
})(request, response);
According to docs setBody requires a JS object and thus if I just pass data variable I get error stating that data cannot be parsed into ScriptableObject.
So with the current code I get below response:
{
"result": {
"data": "\nFirstname,Lastname,Username\nNikhil,vartak,niksofteng\nUnknown,person,anonymous\n"
}
}
And the generated CSV looks like this:
Any idea how to get rid of that XML markup on 1st and 5th line?

The setBody method expects a Javascript object which it is then going to serialize to JSON or XML based on what the client tells it do via Accept header.
In your case you want to produce your own serialized format: CSV. So instead of using the setBody method, use the stream writer interface to directly write to the response stream.
response.setContentType("text/csv");
response.setStatus(200);
var writer = response.getStreamWriter();
writer.write('Firstname,Lastname,Username\n');
writer.write('Nikhil,vartak,niksofteng\n');
etc.
Note you will have to handle all the details of CSV format yourself, including properly encoding any special characters like if you want a field to contain a comma like "Nik,hil".
Cheers,
Silas

Related

How to send a very long xml file as payload in rest API Automation

I want to sent a very long xml as a payload in rest API Automation.
I am using the HTTP client framework.
restClient = new RestClient();
HashMap < String, String > headerMap = new HashMap < String, String > ();
headerMap.put("Content-Type", "application/xml");
headerMap.put("Ocp-Apim-Subscription-Key", "7531bf090b6b49199ec37f9c818dc417");
//jackson API:
ObjectMapper mapper = new ObjectMapper();
Users users = new Users("morpheus", "leader"); //expected users obejct
//object to json file:
You can create object of your XML and set the data using the getter functions() or create a xml file and put it into your project with some pupolated data which will always remain common. Read the external xml file and change it depending on your requirements before making request.
Everything in body can be send as String, save long complex xml to in a file & then convert your XML file to string and pass to that json variable.
JsonRequest{
"name" : "${name}"
}
name= FileUtil.readFileToString(new File(file), StandardCharsets.UTF_8);

Issue with parsing json response having xml attributes

I have a json response using the Http Client Adapter which has the below format
{
"?xml": {
"#version":"1.0",
"#encoding":"utf-8"
},
ArrayOfBusinessTypeAPI {
"#xmlns:xsd":"http://www.w3.org/2001/XMLSchema",
"#xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
...
}
}
I need some information on how the below elements can be defined in the event definition.
1.?xml
2.#version
3.#xmlns:xsd
As per the documentation "#" is used for substitution and : for coassignment.
Can someone please provide any insight as to how this can be done.
I assume you mean in the yaml mapper codec, in which case you can simply quote the keys and this should work:
mapFrom:
- payload.xml: "payload.?xml"
- payload.version: "payload.#version.myField2"
- payload.xmlns_xsd: "payload.#xmlns:xsd"
If you were asking how to declare an event in EPL to handle this response, you don't need to use the exact naming scheme in your event definition. You could have:
event Response {
string xml;
string version;
string xmlns_xsd;
}
And then using the mapper codec map between the two fields like so:
mapFrom:
- payload.xml: "payload.?xml"
- payload.version: "payload.#version.myField2"
- payload.xmlns_xsd: "payload.#xmlns:xsd"
EDIT
So the first thing stopping your event parsing is that your response isn't valid JSON. The line "ArrayOfBusinessTypeAPI {" would need to be ""ArrayOfBusinessTypeAPI": {". You can only use the mapper codec to parse JSON.
The second reason this isn't working is because the content type is set to text/html. Does the JSON codec have filterOnContentType set to true? If so, it won't transform this message.
However, if the JSON is valid and gets processed by the JSON codec, you can correctly map the event like so:
mapFrom:
- payload.id: metadata.requestId
- payload.xml: "payload.?xml"
- payload.version: "payload.xml.#version"
- payload.xsd: "payload.ArrayOfBusinessTypeAPI.#xmlns:xsd"
- payload.xsi: "payload.ArrayOfBusinessTypeAPI.#xmlns:xsi"
- payload.encoding: "payload.xml.#encoding"
Which maps to an event:
event Resp {
dictionary<string, string> xml;
string version;
string xsd;
}

PUT Request not happening at all in Fantom

I am having some trouble with PUT requests to the google sheets api.
I have this code
spreadsheet_inputer := WebClient(`$google_sheet_URI_cells/R3C6?access_token=$accesstoken`)
xml_test := XDoc{
XElem("entry")
{
addAttr("xmlns","http://www.w3.org/2005/Atom")
addAttr("xmlns:gs","http://schemas.google.com/spreadsheets/2006")
XElem("id") { XText("https://spreadsheets.google.com/feeds/cells/$spreadsheet_id/1/private/full/R3C6?access_token=$accesstoken"), },
XElem("link") { addAttr("rel","edit");addAttr("type","application/atom+xml");addAttr("href","https://spreadsheets.google.com/feeds/cells/$spreadsheet_id/1/private/full/R3C6?access_token=$accesstoken"); },
XElem("gs:cell") { addAttr("row","3");addAttr("col","6");addAttr("inputValue","testing 123"); },
},
}
spreadsheet_inputer.reqHeaders["If-match"] = "*"
spreadsheet_inputer.reqHeaders["Content-Type"] = "application/atom+xml"
spreadsheet_inputer.reqMethod = "PUT"
spreadsheet_inputer.writeReq
spreadsheet_inputer.reqOut.writeXml(xml_test.writeToStr).close
echo(spreadsheet_inputer.resStr)
Right now it returns
sys::IOErr: No input stream for response 0
at the echo statement.
I have all the necessary data (at least i'm pretty sure) and it works here https://developers.google.com/oauthplayground/
Just to note, it does not accurately update the calendars.
EDIT: I had it return the response code and it was a 0, any pointers on what this means from the google sheets api? Or the fantom webclient?
WebClient.resCode is a non-nullable Int so it is 0 by default hence the problem would be either the request not being sent or the response not being read.
As you are obviously writing the request, the problem should the latter. Try calling WebClient.readRes() before resStr.
This readRes()
Read the response status line and response headers. This method may be called after the request has been written via writeReq and reqOut. Once this method completes the response status and headers are available. If there is a response body, it is available for reading via resIn. Throw IOErr if there is a network or protocol error. Return this.
Try this:
echo(spreadsheet_inputer.readRes.resStr)
I suspect the following line will also cause you problems:
spreadsheet_inputer.reqOut.writeXml(xml_test.writeToStr).close
becasue writeXml() escapes the string to be XML safe, whereas you'll want to just print the string. Try this:
spreadsheet_inputer.reqOut.writeChars(xml_test.writeToStr).close

Set Mirth destination to send transform data back as a custom ACK

I have a Mirth channel that set up as a web service listener, it receives an ID, build an HL7 query message and send this query and eventually get back an HL7 response.
Channel Name: QueryChanel
Source Connector Type: Web Service Listener
Destination Connector Name: QueryToVista
Destination connector Type:LLP Sender.
This is the typical HL7 response I receive back from my query is as follow:
MSH|~|\&|VAFC RECV|FACILITY|VAFC TRIGGER||20121011141136-0800||ADR~A19|58269|D|2.4|||NE|NE|USA
MSA|AA|1234|
QRD|20121011051137|R|I|500000001|||1^ICN|***500000001***|ICN|NI|
EVN|A1|20121004064809-0800||A1|0^^^^^^^^USVHA\\0363^L^^^NI^TEST FACILITY ID\050\L|20121004064809-0800|050
PID|1|500000001V075322|500000001V075322^^^USVHA\\0363^NI^VA FACILITY ID\050\L~123123123^^^USSSA\\0363^SS^TEST FACILITY ID\050\L~9^^^USVHA\\0363^PI^VA FACILITY ID\050\L||JOHN^DOE^^^^^L|""|19800502|M||""|""^""^""^""^""^^P^""^""~^^""^""^^^N|""|""|""||S|""||123123123|||""|""||||||""||
PD1|||SOFTWARE SERVICE^D^050
ZPD|1||||||||||||||||""
I can get all the above to return if I set my Source's Response From parameter to QueryToVista
However, I want to return only the value 500000001 from the above message. I've tried to play around with the transformer in the QueryChanel destination without success.
Update:
I tried to add a javascriptwriter connector after the QueryToVista connector in the same channel as follow:
var destination = responseMap.get('QueryToVista');
var responseMessage = destination.getMessage();
//Fails with following error: TypeError: Cannot read property "QRD.4" from undefined
var customack = ResponseFactory.getSuccessResponse(responseMessage['QRD']['QRD.4'] ['QRD.4.1'].toString())**
//work but send the whole HL7 message
var customack = ResponseFactory.getSuccessResponse(responseMessage.toString())**
responseMap.put('Barcode', customack);
I can't seem to use the normal transformation to retrieve the element at all.
Thank you.
You're on the right track, but your update illustrates a couple of issues. However, your basic approach of using two destinations is valid, so long as "Synchronize channel" is checked on the Summary tab.
Issue 1
In your example, the HL7 response you are wanting to parse is in pipe delimited HL7 form. In order to access the elements using E4X notation (eg. responseMessage['QRD']['QRD.4']['QRD.4.1']) you must first convert it into an E4X XML object. This can be done in two steps.
Convert the pipe delimited HL7 string into an XML string.
Convert the XML string into an E4X XML object
In a Javascript transformer of the JavaScript Writer (not the Javascript Writer script itself)
var response = responseMap.get("QueryToVista");
var responseStatus = response.getStatus();
// Get's the pipe delimited HL7 string
var responseMessageString = response.getMessage();
if (responseStatus == "SUCCESS")
{
// converts the pipe delimited HL7 string into an XML string
// note: the SerializeFactory object is available for use in transformer
// scripts, but not in the Javascript destination script itself
var responseMessageXMLString = SerializerFactory.getHL7Serializer(false,false,true).toXML(responseMessageString);
// convert the XML string into an E4X XML object
var responseMessageXMLE4X = new XML(responseMessageXMLString);
// grab the value you want
var ack_msg = responseMessageXMLE4X['QRD']['QRD.4']['QRD.4.1'].toString();
channelMap.put('ack_msg', ack_msg)
}
else
{
// responseStatus probably == "FAILURE" but I'm not sure of the full range of possibilities
// take whatever failure action you feel is appropriate
}
Edit**
I don't believe there is an Issue 2. After reviewing your own approach, I played a bit further, and believe I have confirmed that your approach was indeed correct for generating the SOAP reponse. I'm editing this section to reflect simpler code that still works.
In the Javascript Writer script
var barcode = channelMap.get('ack_msg');
var mirthResponse = ResponseFactory.getSuccessResponse(barcode);
responseMap.put('Barcode', mirthResponse);
Thank you very much csj,
I played around and got mine to work and looking at your solution, you pointed out my bottle neck to the issue as well which is the XML part, I did not realize you have to cast it into XML as per the new XML when you already call toXML function :)
Here is my script, though basic I thought I post it up for anyone find it useful down the road.
var destination = responseMap.get('QueryToVista');
var responseMessage = destination.getMessage();
var Xmsg = new XML(SerializerFactory.getHL7Serializer().toXML(responseMessage));
var xml_msg = '<?xml version="1.0" encoding="utf-8" ?>'+
'<XML><Patient Name="'+Xmsg['PID']['PID.5']['PID.5.1']+
'" Barcode="'+Xmsg['QRD']['QRD.8']['QRD.8.1']+'" /></XML>';
var sResp = ResponseFactory.getSuccessResponse(xml_msg)
responseMap.put('Response', sResp);

Accessing data from response of FB.api()

I am having difficulty accessing the returned JSON response data from the new Facebook JS SDK new Graph API calls.
For instance, in some of their docs where they are using the old way of using the SDK , they get a pointer to the data by response[0]
but here, it's showing that you need to use response.data[0] instead: http://developers.facebook.com/tools/console/ (click on fb.api — photo-albums)
So which is it? I know that with my code below, if I try using response[0] type of syntax to get at the returned JSON I get undefined.
If I use response[0].length I also get undefined
But if I try response.data[0].length I get 2 which I guess is the returned JSON or my 2 albums..I just don't know how to play with this returned object in terms of syntax and manipulating it, its properties, etc.
I want to in the end parse out the returned JSON using the jQuery parseJSON method but have no clue how to even pass the right syntax here for the response and just use that response object.
FB.api(uri, function(response)
{
alert("response: " + response);
// check for a valid response
if (response == "undefined" || response == null || !response || response.error)
{
alert("error occured");
return;
}
alert("response length: " + response.data.length);
}
this alert gave me 2 which makes sense. I have 2 albums.
then I tried something like response.data[0] and tried a jQuery parseJSON(response.data) or parseJSON(response.data[0]) on that and it does not work. So can someone explain the response object here as in regards to Facebook I guess? I see no docs about how to use that returned object at all and how it's constructed.
UPDATED:
Ok, so here's the entire parsing method attempt that I've stubbed out so far. I don't know if the jQuery parsing is 100% good code yet, I sort of stubbed that out but I can't even test that until I figure out how to use this response object coming back. I know it is returning JSON because I parsed another facebook response object in another method in the JS SDK so pretty sure that response[0] or response.data[0] will give you the JSON string.
function GetAllFacebookAlbums(userID, accessToken)
{
alert("inside GetAllFacebookAlbums(userID, acessToken)");
var dFacebookAlbums = {}; // dictionary
var uri = "/" + userID + "/albums?access_token=" + accessToken;
//var uri = "/me/albums";
alert("get albums uri: " + uri);
FB.api(uri, function(response)
{
alert("response: " + response);
// check for a valid response
if (response == "undefined" || response == null || !response || response.error)
{
alert("error occured");
return;
}
alert("response length: " + response.data.length);
for (var i=0, l=response.data.length; i<l; i++)
{
alert("response[key]: " + response.data[i].Name);
}
// parse JSON from response
var dJSONObjects = jQuery.parseJSON(response.data);
alert("dJSONObjects: " + dJSONObjects);
if (dJSONObjects.length == 0)
return;
// iterate through the dictionary of returned JSON objects
// and transform each to a custom facebookAlbum object
// then add each new FacebookAlbum to the final dictionary
// that will return a set of facebookAlbums
$.each(json.attributes, function () {
// add a new album to the dictionary
aFacebookAlbums[i] = FacebookAlbum(
jsonObject["id"],
jsonObject["name"],
jsonObject["location"],
jsonObject["count"],
jsonObject["link"]
);
});
});
return dFacebookAlbums;
}
It depends on the API being used. For the new Graph API single objects come back as top level object: http://graph.facebook.com/naitik -- where as collections come back with a top level data property which is an Array: http://graph.facebook.com/zuck/feed. There's also introspection to make things somewhat easier: http://developers.facebook.com/docs/api#introspection. FQL is the other popular API call, and this is where the top level response is array (think rows in SQL) which is why some examples use response[0]. Easiest thing is to just look at the response in your browser or via curl and see what it looks like.
just to clarify for all you folks who are new to FB.api (as I am) graph queries return different shaped data ... here are two examples:
FB.api('me/' function(returnData) { } ) would put the following data into returnData
{
"id": "592529630",
"name": "Hugh Abbott",
"first_name": "Hugh",
"last_name": "Abbott",
}
then if I said returnData.first_name I would get "Hugh"
If however my query was about my friends, I might run the following query
FB.api('me/friends/' function(returnData) { } )
And the shape of my data is now different:
"data": [
{
"name": "Tom Bell",
"id": "36801805"
},
{
"name": "Michael Royce",
"id": "199712888"
},
]
... so returnData is now a array ... in order to retrieve values, I would do something like the following.
returnData.data[0].name this would return "Tom Bell"
I hope this helps, as I spent a few hours wondering where I had gone wrong ... it turns out, it is all in the shape of the data !!!! good luck my friends.
Hugh
In general, the JS SDK doesn't return JSON object but it returns an object which is structured similar to the JSON Object.
Say for example : One is polling for user events data and according to the GRAPH API reference (http://developers.facebook.com/docs/reference/api/event), the returned data will have attributes as given http://developers.facebook.com/docs/reference/api/event.
The JSON object for the events data would be like this if you are using PHP SDK
Array ( [data] => Array ( [0] => Array ( [name] => sample event [start_time] => 2010-08-09T22:00:00+0000 [end_time] => 2010-08-10T01:00:00+0000 [location] => at office\ [id] => xxxxxxxx [rsvp_status] => attending )) [paging] => Array ( [previous] => hyperlink [next] => hyperlink ) )
But if you are using JS SDK, then the returned response will be like this
response.data[0...n].attributes of the particular table which you are accessing.
So, in the case of event table it will be like this :
response.data[0...n].name or response.data[0...n].id, response.data[0...n].end_time, etc
Did this ever get figured out. No one accepted anything.
alert("response[key]: " + response.data[i].Name);
The above code has Name and not name. Also, as Matti pointed out above, this works:
response.data[0].name
Just my two cents. #CoffeeAddict, accept answers to show some appreciation... Seems like someone with you rep would appreciate that. :o)
I haven't looked at the API, but I doubt FB would give you JSON encoded strings in an array. Have you tried just accessing response.data[0].someproperty?
If there is no error, then response.data should be the stuff you want (this will be an array in most cases) if you are using the new graph api. You could always just alert the JSON string if you are unsure what you are getting back.
I'm sure this must not be an issue anymore considering the Graph API explorer clearly displays the data in the form that it is returned. You are right about the difference in structure of the responses, but personally it has been useful to see what data is returned using the explorer and use the syntax accordingly.