Groovy ws-lite REST post with json payload - groovy

I am trying to call a REST API via the ws-lite. Get works great but calling a post with a json payload not working. Bit of a noob but from github notes wiki i am not sure https://github.com/jwagenleitner/groovy-wslite
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.rest.*
import groovy.json.JsonBuilder
def client = new RESTClient("https://d.la10.salesforceliveagent.com/chat/rest")
def response = client.get(path:'/System/SessionId', headers:['X-LIVEAGENT- API-VERSION':'36','X-LIVEAGENT-AFFINITY':'null'])
def skey = response.json.key
def sid = response.json.id
def stoken = response.json.affinityToken
client.post(path:'/Chasitor/ChasitorInit', headers:['X-LIVEAGENT-API-VERSION':'36','X-LIVEAGENT-SESSION-KEY':skey,'X-LIVEAGENT-AFFINITY':stoken,'X-LIVEAGENT-SEQUENCE':'1'])
{
type ContentType.application/json
json {
"organizationId": "00D28000000f5N9",
"deploymentId": "572280000008R6L",
"buttonId": "573D000000000OC",
"agentId": "005B0000000F3b2",
"doFallback": true,
"sessionId": sid,
"userAgent": "Lynx/2.8.8",
"screenResolution": "2560x1440",
"visitorName": "Jon A",
"prechatDetails": [],"prechatEntities": [],
"receiveQueueUpdates": true,
"isPost": true
}
}
Curious if anyone has an example using for a post with REST via ws-lite from groovy. I simply get compilation failures based on the json format. Any insight appreciated

The json method inside the post block is expecting a Map as the parameter so the following would work (basically change the braces to brackets):
....
....
client.post(path:'/Chasitor/ChasitorInit', headers:['X-LIVEAGENT-API-VERSION':'36','X-LIVEAGENT-SESSION-KEY':skey,'X-LIVEAGENT-AFFINITY':stoken,'X-LIVEAGENT-SEQUENCE':'1'])
{
type ContentType.application/json
json ["organizationId": "00D28000000f5N9",
"deploymentId": "572280000008R6L",
"buttonId": "573D000000000OC",
"agentId": "005B0000000F3b2",
"doFallback": true,
"sessionId": sid,
"userAgent": "Lynx/2.8.8",
"screenResolution": "2560x1440",
"visitorName": "Jon A",
"prechatDetails": [],"prechatEntities": [],
"receiveQueueUpdates": true,
"isPost": true]
}
Since the Map is the only parameter you should also be able to omit the brackets.

Related

Missing element in SOAP API request using Python's Zeep, but the element is in the request dictionary

i'm using Zeep to interact with Workday's SOAP API to edit a someone's Workday username. Here is the following request body to the Human Resources WSDL, v37.2
request_dict = {
"Workday_Account_for_Worker_Update": {
"Worker_Reference": {
"Employee_Reference": {
"Integration_ID_Reference": {
"ID": {
"type": "WD-EMPLID",
"_value_1": user_id
}
}
}
},
"Workday_Account_for_Worker_Data": {
"User_Name": username
}
}
}
response = client.service.Update_Workday_Account(request_dict)
The error message i receive is
zeep.exceptions.ValidationError: Missing element Workday_Account_for_Worker_Data (Workday_Account_for_Worker_Update.Workday_Account_for_Worker_Data), but the element is clearly there. Anyone have any idea what I'm doing wrong?
You are not using the correct method signature to perform the call.
If you do a:
python -mzeep https://community.workday.com/sites/default/files/file-hosting/productionapi/Human_Resources/v37.2/Human_Resources.wsdl > output.txt
and you look inside the produced output.txt file, you will see that Update_Workday_Account has this signature:
Update_Workday_Account(
Worker_Reference: ns0:Worker_ReferenceType,
Non_Worker_Reference: ns0:RoleObjectType,
Workday_Account_for_Worker_Data: ns0:Workday_Account_for_Worker_DataType,
version: xsd:string,
_soapheaders={header: ns0:Workday_Common_HeaderType}
) -> None
so your code should probably be something like this:
worker_reference = {
"Employee_Reference": {
"Integration_ID_Reference": {
"ID": {
"type": "WD-EMPLID",
"_value_1": user_id
}
}
}
}
workday_account_for_worker_data = {
"User_Name": username
}
client.service.Update_Workday_Account(worker_reference, None, workday_account_for_worker_data)
I can't really test the call from my side so you should substitute appropriate parameters on your side before making the request.

Why does ga:clientId dimension request return empty array when using python3 google analytics v4?

Trying to get clientId from google analytics currently via python code:
def get_report(analytics):
return analytics.reports().batchGet(
body={
"reportRequests": [
{
"viewId": VIEW_ID,
"dateRanges": [{"startDate": "7daysAgo", "endDate": "today"}],
"dimensions": [{"name": "ga:pagePath"}, {"name": "ga:clientId"}],
"metrics": [{"expression": "ga:pageViews"}, {"expression": "ga:sessions"},
{"expression": "ga:avgTimeOnPage"}]
}]
}
).execute()
this code returns empty array, if I remove:
{"name": "ga:clientId"}
It works fine, and returns all the data. Also using Java, I can get the clientID number fine in such fashion:
Dimension clientId = new Dimension().setName("ga:clientId");
ReportRequest request = new ReportRequest()
.setViewId(VIEW_ID)
.setDateRanges(Arrays.asList(dateRange))
.setMetrics(lstMetrics)
.setDimensions(lstDim);
ArrayList<ReportRequest> requests = new ArrayList<ReportRequest>();
requests.add(request);
// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest()
.setReportRequests(requests);
// Call the batchGet method.
GetReportsResponse response = service.reports().batchGet(getReport).execute();
// Return the response.
return response;
But python fails to produce same data response.

Training Microsoft Custom Vision model via rest api

I am working on a simple nodejs console utility that will upload images for the training of a Custom Vision model. I do this mainly because the customvision web app won't let you tag multiple images at once.
tl;dr: How to post images into the CreateImagesFromFiles API endpoint?
I cannot figure out how to pass images that I want to upload. The documentation just defines a string as a type for one of the properties (content I guess). I tried passing path to local file, url to online file and even base64 encoded image as a string. Nothing passed.
They got a testing console (blue button "Open API testing console" at the linked docs page) but once again... it's vague and won't tell you what kind of data it actually expects.
The code here isn't that relevant, but maybe it helps...
const options = {
host: 'southcentralus.api.cognitive.microsoft.com',
path: `/customvision/v2.0/Training/projects/${projectId}/images/files`,
method: 'POST',
headers: {
'Training-Key': trainingKey,
'Content-Type': 'application/json'
}
};
const data = {
images: [
{
name: 'xxx',
contents: 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAEklEQVR42mP8z8AARKiAkQaCAFxlCfyG/gCwAAAAAElFTkSuQmCC',
tagIds: [],
regions: []
}
],
tagIds: []
}
const req = http.request(options, res => {
...
})
req.write(JSON.stringify(data));
req.end();
Response:
BODY: { "statusCode": 404, "message": "Resource not found" }
No more data in response.
I got it working using the "API testing console" feature, so I can help you to identify your issue (but sorry, I'm not expert in node.js so I will guide you with C# code)
Format of content for API
You are right, the documentation is not clear about the content the API is waiting for. I made some search and found a project in a Microsoft's Github repository called Cognitive-CustomVision-Windows, here.
What is saw is that they use a class called ImageFileCreateEntry whose signature is visible here:
public ImageFileCreateEntry(string name = default(string), byte[] contents = default(byte[]), IList<System.Guid> tagIds = default(IList<System.Guid>))
So I guessed it's using a byte[].
You can also see in their sample how they did for this "batch" mode:
// Or uploaded in a single batch
var imageFiles = japaneseCherryImages.Select(img => new ImageFileCreateEntry(Path.GetFileName(img), File.ReadAllBytes(img))).ToList();
trainingApi.CreateImagesFromFiles(project.Id, new ImageFileCreateBatch(imageFiles, new List<Guid>() { japaneseCherryTag.Id }));
Then this byte array is serialized with Newtonsoft.Json: if you look at their documentation (here) it says that byte[] are converted to String (base 64 encoded). That's our target.
Implementation
As you mentioned that you tried with base64 encoded image, I gave it a try to check. I took my StackOverflow profile picture that I downloaded locally. Then using the following, I got the base64 encoded string:
Image img = Image.FromFile(#"\\Mac\Home\Downloads\Picto.jpg");
byte[] arr;
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
arr = ms.ToArray();
}
var content = Convert.ToBase64String(arr);
Later on, I called the API with no tags to ensure that the image is posted and visible:
POST https://southcentralus.api.cognitive.microsoft.com/customvision/v2.2/Training/projects/MY_PROJECT_ID/images/files HTTP/1.1
Host: southcentralus.api.cognitive.microsoft.com
Training-Key: MY_OWN_TRAINING_KEY
Content-Type: application/json
{
"images": [
{
"name": "imageSentByApi",
"contents": "/9j/4AAQSkZJRgA...TOO LONG FOR STACK OVERFLOW...",
"tagIds": [],
"regions": []
}
],
"tagIds": []
}
Response received: 200 OK
{
"isBatchSuccessful": true,
"images": [{
"sourceUrl": "imageSentByApi",
"status": "OK",
"image": {
"id": "GENERATED_ID_OF_IMAGE",
"created": "2018-11-05T22:33:31.6513607",
"width": 328,
"height": 328,
"resizedImageUri": "https://irisscuprodstore.blob.core.windows.net/...",
"thumbnailUri": "https://irisscuprodstore.blob.core.windows.net/...",
"originalImageUri": "https://irisscuprodstore.blob.core.windows.net/..."
}
}]
}
And my image is here in Custom Vision portal!
Debugging your code
In order to debug, you should 1st try to submit your content again with tagIds and regions arrays empty like in my test, then provide the content of the API reply

CDON API RESTful Api GET request

I'm currently working on fetching customer data from cdon, it's an e-commerce platform. They have their API documentation here:
CDON Api Docu
First let me show you my code:
myToken = '<token here>'
myUrl = 'https://admin.marketplace.cdon.com/api/reports/d8578ef8-723d-46cb-bb08-af8c9b5cca4c'
head = {'Authorization': 'token {}'.format(myToken),
'Status':'Online',
'format':'json'}
filters = '?filter={"Status":["Online"],"format": ["json"] }}'
response = requests.get(myUrl + filters, headers=head)
report = response.json()
print(report.products)
This is returning only the parameters. like for example at at this JSON: CDON Github
Status has a value Online this online is a group of itemsthat I only want to get.
What I'm trying to get is a response like this:
{
"Products": [
{
"SKU": "322352",
"Title": "Fabric Cover",
"GTIN": "532523626",
"ManufacturerArticleNumber": "",
"StatusCDON": "Online",
"ExposeStatusCDON": "Buyable",
"InStock": 0,
"InStockCDON": 0,
"CurrentPriceSE": null,
"OrdinaryPriceSE": null,
"CurrentPriceCDONSE": 299.0000,
"OrdinaryPriceCDONSE": null,
"CurrentPriceDK": null,
"OrdinaryPriceDK": null,
"CurrentPriceCDONDK": null,
"OrdinaryPriceCDONDK": null,
"CurrentPriceNO": null,
"OrdinaryPriceNO": null,
"CurrentPriceCDONNO": null,
"OrdinaryPriceCDONNO": null,
"CurrentPriceFI": null,
"OrdinaryPriceFI": null,
"CurrentPriceCDONFI": null,
"OrdinaryPriceCDONFI": null
},
Which means the full list of the items that are Online
How should I put this... among all the API's I tried this one is very confusing, is this even RestFul? If I can achieve the python equivalent of this C# sample code:
public string Post(Guid repordId, string path)
{
var filter = new JavaScriptSerializer().Serialize(new
{
States = new[] { "0" } // Pending state
});
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair("ReportId", repordId.ToString()),
new KeyValuePair("format", "json"),
new KeyValuePair("filter", filter)
});
var httpClient = new HttpClient() { BaseAddress = new Uri("https://admin.marketplace.cdon.com/") };
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("api", ApiKey);
var response = httpClient.PostAsync(path, content).Result;
response.EnsureSuccessStatusCode();
return response.Content.ReadAsStringAsync().Result;
}
I may be able to undestand how this API works, the response that I got was taken manually from their report function in JSON format.
Image
I made many attempts and at that code ( my code ) I stopped, being on this for 4 hours made me give up and ask. Trust that I have searched as many references as I could. It's really confusing.
How do I get the response that I want? Filtering via url? or via header? is this even restful? Help T_T
The documentation states in the first line, emphasis mine:
In order to generate a report you perform a POST call to the reports API with the parameters you wish to use for the report.
Your Python code does not make a POST request, you are trying a GET request. The documentation goes on
[...] to filter on Swedish orders you set the CountryCodes
attribute to “Sweden” and to get returned and cancelled orders you set
the States attribute to 2 and 3. So in the end the filter would look
like this:
{
"CountryCodes": [ "Sweden" ],
"States": ["2", "3"]
}
So you need to prepare a filter object (a dictionary in Python) with the filters you want. Luckily the Python syntax for dictionaries is equivalent (Python is flexible and also allows single-quoted strings):
filter = {
'CountryCodes': [ 'Sweden' ],
'States': [ '0' ]
}
The documentation goes on
You then post the parameters as form data (content-type:
application/x-www-form-urlencoded) so the request body would look like
this:
ReportId=d4ea173d-bfbc-48f5-b121-60f1a5d35a34&format=json&filter={"CountryCodes":["Sweden"],"States":["2","3"]}
application/x-www-form-urlencoded is the default for HTTP post, the requests module knows that and does this for you automatically. All you need to do is to prepare a data dict which will contain the data you want to post.
data = {
'ReportId': 'd4ea173d-bfbc-48f5-b121-60f1a5d35a34',
'format': 'json'
'filter': json.dumps(filter)
}
The filter parameter is supposed to be in JSON format. You must encode that yourself via json.dumps().
import json
head = { ... as above }
filter = { ... as above }
data = { ... as above }
response = requests.post(url, data, header=head)
I'll leave figuring out setting the Authorization header properly as an exercise for you. Partly because it isn't hard, partly because I have no intention of creating an API key with this website just for testing this and partly because it's entirely possible that your current header already works.

Convert WebService Response into Json Arrary and Jsobobject using Groovy

I am testing RESTful webservice using SoapUI. We use Groovy for that.
I am using jsonslurper to parse the response as Object type.
Our reponse is similar to this:
{
"language":[
{
"result":"PASS",
"name":"ENGLISH",
"fromAndToDate":null
},
{
"result":"FAIL",
"name":"MATHS",
"fromAndToDate": {
"from":"02/09/2016",
"end":"02/09/2016"
}
},
{
"result":"PASS",
"name":"PHYSICS",
"fromAndToDate":null
}
]
}
After this, I stuck up on how to.
Get Array (because this is array (starts with -language)
How to get value from this each array cell by passing the key (I should get the value of result key, if name='MATHS' only.)
I could do it using Java, but as just now learning Groovy I could not understand this. We have different keys with same names.
You can just parse it in to a map, then use standard groovy functions:
def response = '''{
"language":[
{"result":"PASS","name":"ENGLISH","fromAndToDate":null},
{"result":"FAIL","name":"MATHS","fromAndToDate":{"from":"02/09/2016","end":"02/09/2016"}},
{"result":"PASS","name":"PHYSICS","fromAndToDate":null}
]
}'''
import groovy.json.*
// Parse the Json string
def parsed = new JsonSlurper().parseText(response)
// Get the value of "languages" (the list of results)
def listOfCourses = parsed.language
// For this list of results, find the one where name equals 'MATHS'
def maths = listOfCourses.find { it.name == 'MATHS' }

Resources