Adobe Analytics 2.0 API endpoint to get report suite events, props, and evars - adobe

I'm having a hard time finding a way in the 2.0 API that I can get a list of Evars, Props and Events for a given report suite. The 1.4 version has the reportSuite.getEvents() endpoint and similar for Evars and Props.
Please let me know if there is a way to get the same data using the 2.0 API endpoints.

The API v2.0 github docs aren't terribly useful, but the Swagger UI is a bit more helpful, showing endpoints and parameters you can push to them, and you can interact with it (logging in with your oauth creds) and see requests/responses.
The two API endpoints in particular you want are metrics and dimensions. There are a number of options you can specify, but to just get a dump of them all, the full endpoint URL for those would be:
https://analytics.adobe.io/api/[client id]/[endpoint]?rsid=[report suite id]
Where:
[client id] - The client id for your company. This should be the same value as the legacy username:companyid (the companyid part) from v1.3/v1.4 API shared secret credentials, with the exception that it is suffixed with "0", e.g. if your old username:companyid was "crayonviolent:foocompany", the [client id] would be "foocompany0", because..reasons? I'm not sure what that's about, but it is what it is.
[endpoint] - Value should be "metrics" to get the events, and dimensions to get the props and eVars. So you will need to make 2 API endpoint requests.
[rsid] - The report suite id you want to get the list of events/props/eVars from.
Example:
https://analytics.adobe.io/api/foocompany0/metrics?rsid=fooglobal
One thing to note about the responses: they aren't like the v1.3 or v1.4 methods where you query for a list of only those specific things. It will return a json array of objects for every single event and dimension respectively, even the native ones, calculated metrics, classifications for a given dimension, etc. AFAIK there is no baked in way to filter the API query (that's in any documentation I can find, anyways..), so you will have to loop through the array and select the relevant ones yourself.
I don't know what language you are using, but here is a javascript example for what I basically do:
var i, l, v, data = { prop:[], evar: [], events:[] };
// dimensionsList - the JSON object returned from dimensions API call
// for each dimension in the list..
for (i=0,l=dimensionsList.length;i<l;i++) {
// The .id property shows the dimension id to eval
if ( dimensionsList[i].id ) {
// the ones we care about are e.g. "variables/prop1" or "variables/evar1"
// note that if you have classifications on a prop or eVar, there are entries
// that look like e.g. "variables/prop1.1" so regex is written to ignore those
v = (''+dimensionsList[i].id).match(/^variables\/(prop|evar)[0-9]+$/);
// if id matches what we're looking for, push it to our data.prop or data.evar array
v && v[1] && data[v[1]].push(dimensionsList[i]);
}
}
// metricsList - the JSON object returned from metrics API call
// basically same song and dance as above, but for events.
for (var i=0,l=metricsList.length;i<l;i++) {
if ( metricsList[i].id ) {
// events ids look like e.g. "metrics/event1"
var v = (''+metricsList[i].id).match(/^metrics\/event[0-9]+$/);
v && data.events.push(metricsList[i]);
}
}
And then the result data object will have data.prop,data.evar, and data.events, each an array of the respective props/evars/events.
Example object entry for an data.events[n]:
{
"id": "metrics/event1",
"title": "(e1) Some event",
"name": "(e1) Some event",
"type": "int",
"extraTitleInfo": "event1",
"category": "Conversion",
"support": ["oberon", "dataWarehouse"],
"allocation": true,
"precision": 0,
"calculated": false,
"segmentable": true,
"supportsDataGovernance": true,
"polarity": "positive"
}
Example object entry for an data.evar[n]:
{
"id": "variables/evar1",
"title": "(v1) Some eVar",
"name": "(v1) Some eVar",
"type": "string",
"category": "Conversion",
"support": ["oberon", "dataWarehouse"],
"pathable": false,
"extraTitleInfo": "evar1",
"segmentable": true,
"reportable": ["oberon"],
"supportsDataGovernance": true
}
Example object entry for a data.prop[n]:
{
"id": "variables/prop1",
"title": "(c1) Some prop",
"name": "(c1) Some prop",
"type": "string",
"category": "Content",
"support": ["oberon", "dataWarehouse"],
"pathable": true,
"extraTitleInfo": "prop1",
"segmentable": true,
"reportable": ["oberon"],
"supportsDataGovernance": true
}

Related

Read write AD user custom attributes

I want to store some additional user attributes in form of key and value pairs to all the AD users, for example: 'colorTheme:red', 'userLang:english' etc.
I have added these custom attributes using the Azure AD B2C > User Attributes
I am trying to Read and Write as per the below link.
https://learn.microsoft.com/en-us/graph/extensibility-open-users
I did try using the Graph API calls:
GET https://graph.microsoft.com/v1.0/users?$select=displayName&$expand=extensions
I do get the user details but don't get custom attribute
GET https://graph.microsoft.com/v1.0/me/extensions
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('ad-user-id')/extensions",
"value": []
}
How do I get and set the value for the custom attribute?
Is there any other way of storing addition user properties?
The following steps can be used for getting extension properties (custom attributes) defined for a user in Azure AD B2C
Call the following endpoint to get all the existing extension properties. Replace the {{extensionappobjectidwithoutdashes}} with your extension app's object Id without dashes.
https://graph.microsoft.com/v1.0/applications/{{extensionappobjectidwithoutdashes}}/extensionProperties
This will give result that looks something like this. I have removed the guids
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#applications('extensionappobjectidwithoutdashes')/extensionProperties",
"value": [
{
"id": "",
"deletedDateTime": null,
"appDisplayName": "",
"dataType": "String",
"isSyncedFromOnPremises": false,
"name": "extension_<extensionappIdwithoutdashes>_extensionAttribute1",
"targetObjects": [
"User"
]
},
{
"id": "",
"deletedDateTime": null,
"appDisplayName": "",
"dataType": "String",
"isSyncedFromOnPremises": false,
"name": "extension_<extensionappIdwithoutdashes>_extensionAttribute2",
"targetObjects": [
"User"
]
}
]
}
While calling graph api to get user details, add the name of the extension attribute in the select query
https://graph.microsoft.com/v1.0/users?$select=displayName,extension_extension_<extensionappIdwithoutdashes>_extensionAttribute1,extension_extension_<extensionappIdwithoutdashes>_extensionAttribute2
Notes
Use the following docs to see how to create extension properties using ms graph apis
extensionProperty resource type
The extensionappobjectidwithoutdashes and extensionappIdwithoutdashes are different guids. Find them in App Registrations > b2c-extensions-app

How to test pact with null data

I am aware of that PACT expects provider data need to be in our control, but I am facing following situation
I have pact contract for multiple consumers, all have some mandatory attribute and some are optional attribute, but business logic suppress all the attribute which are having null value, but according to contract I would still be needing that value as null,
what should I do for it?
Edit 1:
i.e let's say below my contract looks
consumer sent request with below params:
{ "method": "GET", "path" : "/pathOfApi", "headers":{ "accept": "json" } }
Provider responds with below data:
{ "Status": 200,
"body" :[
{"country" : "string",
"countryId" :"string",
"postalcode": "string",
"addressLine1" :"string",
"addressLine2" : "string"
"customerName" : "string",
"customerId" : "string"
}
]
now not all customer has address line 2, now in production if addressLine 2 is null it won't be present in output of api, but for our contract field should be present with null
If your provider does not return a field, but the consumer is expecting null, then either the consumer needs to change their expectation (because it's incorrect) or the provider should update its implementation to return null values.
Just because a consumer asks for something doesn't mean you need to do it!
If in some instances the field is present and other it is not, you need to write two tests to cover each case. I'd suggest covering one case with all of the fields, and another with the minimum set of fields (see https://docs.pact.io/faq/#why-is-there-no-support-for-specifying-optional-attributes).

In Geocoder here-api what are the different types of View

I am moving from Google to Here-api Geocoding service.In the Response JSON object there is a property View which is an array. I was not able to find in the documentation what types of objects might be in this collection. It seems that there is a type-_type property for every View and from all my testing I got only one object inside this array and it is always from the same type "_type": "SearchResultsViewType". My questions are:
Is it possible this collection that View collection to contain more than one object? Are they from the same "_type" or from a different "_type"?In short, besides probably ViewId how are different Views objects separated?
I made numerous requests to Geogoder API with switching on and off different parameters. I have searched here and in the API documentation.
This is how the Response object is looking now
{
"Response": {
"MetaInfo": {
"Timestamp": "2019-04-18T11:48:31.306+0000"
},
"View": [
{ "_type": "SearchResultsViewType",
"ViewId": 0,
"Result": .....

How can I retrieve a RingCentral call recording from a monitored incoming call?

I'm monitoring incoming calls on RingCentral by listening for the Call Session Notifications (CSN) telephony/sessions event filter:
/restapi/v1.0/account/~/extension/~/telephony/sessions
From this, I will receive events like the following. The recordings property will appear to indicate a recording is available. How can I retrieve this recording?
{
"uuid":"12345678901234567890",
"event":"/restapi/v1.0/account/11111111/extension/22222222/telephony/sessions",
"timestamp":"2019-03-08T22:30:40.059Z",
"subscriptionId":"11112222-3333-4444-5555-666677778888",
"ownerId":"33333333",
"body":{
"sequence":7,
"sessionId":"1234567890",
"telephonySessionId":"1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
"serverId":"10.11.12.13.TAM",
"eventTime":"2019-03-08T22:30:39.938Z",
"parties":[
{
"accountId":"11111111",
"extensionId":"22222222",
"id":"cs12345678901234567890-2",
"direction":"Inbound",
"to":{
"phoneNumber":"+16505550100",
"name":"Jane Doe",
"extensionId":"22222222"
},
"from":{
"phoneNumber":"+14155550100",
"name":"John Smith"
},
"recordings":[
{
"id":"44444444",
"active":false
}
],
"status":{
"code":"Answered",
"rcc":false
},
"missedCall":false,
"standAlone":false,
"muted":false
}
],
"origin":{
"type":"Call"
}
}
}
There are two ways to retrieve the recording using information in the Call Session Notification (CSN) event, specifically the recordings[0].id property and the sessionID property.
retrieving a full media URL by calling the call-log endpoint with the sessionId property
manually creating recording media URL using the recordings[0].id property.
Note 1: While the call is ongoing, the recording will not be available for retrieval, even when the recording id is present in the Call Session Notification event. The recording will be available to be retrieved shortly after the call concludes.
Note 2: Call recordings can be in MP3 or WAV format determined by the company. To distinguish check the response Content-Type header for the MIME type when retrieving the recording media file.
1) Retrieving Full Medial URL via Call Log API
Making an intermediate API call to the call-log API has the dual benefits of being the official approach for receiving a media URL an providing more metadata for the call. In this approach, the recording.id in the call-log record will match the recordings[0].id property in the Call Session Notification event.
Both the company account and user extension call-log APIs can be called with the sessionId parameter from the event as shown:
GET /restapi/v1.0/account/~/call-log?sessionId={sessionId}
GET /restapi/v1.0/account/~/extension/~/call-log?sessionId={sessionId}
In this example, the sessionId is 1234567890 so you would have a Company Call Log API URL as follows
GET /restapi/v1.0/account/~/call-log?sessionId=1234567890
The response object will have a recording property that provides hypermedia links to get the media file. The file can be WAV or MP3 format which is communicated in the response Content-Type header.
{
"uri": "https://platform.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/call-log?view=Simple&sessionId=1234567890&page=1&perPage=100",
"records": [
{
"uri": "https://platform.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/call-log/1234567890ABCDEFGabcdefgh?view=Simple",
"id": "1234567890ABCDEFGabcdefgh",
"sessionId": "1234567890",
"startTime": "2019-03-08T22:30:29.505Z",
"duration": 35,
"type": "Voice",
"direction": "Inbound",
"action": "Phone Call",
"result": "Accepted",
"to": {
"phoneNumber": "+16505550100",
"name": "Jane Doe"
},
"from": {
"phoneNumber": "+14155550100",
"name": "John Smith",
"location": "San Francisco, CA"
},
"recording": {
"uri": "https://platform.ringcentral.com/restapi/v1.0/account/11111111/recording/44444444",
"id": "44444444",
"type": "OnDemand",
"contentUri": "https://media.ringcentral.com/restapi/v1.0/account/111111111/recording/44444444/content"
},
"extension": {
"uri": "https://platform.ringcentral.com/restapi/v1.0/account/111111111/extension/22222222",
"id": 22222222
},
"reason": "Accepted",
"reasonDescription": "The call connected to and was accepted by this number."
}
],
"paging": {
"page": 1,
"perPage": 100,
"pageStart": 0,
"pageEnd": 0
},
"navigation": {
"firstPage": {
"uri": "https://platform.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/call-log?view=Simple&sessionId=1234567890&page=1&perPage=100"
},
"lastPage": {
"uri": "https://platform.ringcentral.com/restapi/v1.0/account/11111111/extension/22222222/call-log?view=Simple&sessionId=1234567890&page=1&perPage=100"
}
}
}
2) Manually Creating Media URL
You can call the Recording API endpoint and retrieve the media directly by manually constructing the recording URL as follows:
https://media.ringcentral.com/restapi/v1.0/account/{accountId}/recording/{recordingId}/content
In this example, the accountId is 11111111 and the recordingId is 44444444 for the following:
https://media.ringcentral.com/restapi/v1.0/account/11111111/recording/44444444/content
The accountId in the URL path can be set to the currently authorized user's account using ~. Alternately, it can be set explicitly by extracting the accountId from the event property or using the accountId property in the relevant party object. Using ~ is the recommended way to set accountId.
Note: This this approach can be quick, it may be error prone as RingCentral has changed the media hostname once in the past. While there are no anticipated, future changes, calling the call-log API and retrieving the full media URL from the response is the safer and recommended approach. See below for this approach. This is only included as some people will try this and potentially run into issues later.
3) Hybrid Approach
The first approach of calling the call-log end point is the recommended approach, however, it involves an extra API call and most of the time the second approach should work fine.
A hybrid approach is to construct the URL as in approach 2 and then fall back to approach 1 if approach 2 returns a 404 or other error.

"Reverse formatting" Riak search results

Let's say I have an object in the test bucket in my Riak installation with the following structure:
{
"animals": {
"dog": "woof",
"cat: "miaow",
"cow": "moo"
}
}
When performing a search request for this object, the structure of the search results is as follows:
{
"responseHeader": {
"status": 0,
"QTime": 3,
"params": {
"q": "animals_cow:moo",
"q.op": "or",
"filter":"",
"wt": "json"
}
},
"response": {
"numFound": 1,
"start": 0,
"maxScore": "0.353553",
"docs": [
{
"id": "test",
"index": "test",
"fields": {
"animals_cat": "miaow",
"animals_cow": "moo",
"animals_dog": "woof"
},
"props": {}
}
]
}
}
As you can see, the way the object is stored, the cat, cow and dog keys are nested within animals. However, when the search results come back, none of the keys are nested, and are simply separated by _.
My question is this: Is there any way provided by Riak to "reverse format" the search, and return the fields of the object in the correct (nested) format? This becomes a problem when storing and returning user data that might possibly contain _.
I do see that the latest version of Riak (beta release) provides a search schema, but I can't seem to see whether my question would be answered by this.
What you receive back in the search result is what the object looked like after passing through the json analyzer. If you need the data formatted differently, you can use a custom analyzer. However, this will only affect newly put data.
For existing data, you can use the id field and issue a get request for the original object, or use the solr query as input to a MapReduce job.

Resources