Get contacts by IDs in batch in Microsoft Graph - microsoft-graph-api

I have a list of IDs which I want to pull the corresponding contacts from Microsoft Graph. I tried filtering with https://graph.microsoft.com/v1.0/me/contacts?$filter=Id eq 'my-id-here' or Id eq 'other-id-here' but it says
ErrorInvalidProperty The property 'Id' does not support filtering.
I know than I can query by calling https://graph.microsoft.com/v1.0/me/contacts/my-id-here but I want to request multiple at once to minimize round trips.

You can use batch processing to execute multiple requests. For each request you need to provide a request id, a http method and a request url. Sample request:
URL: https://graph.microsoft.com/v1.0/$batch
Http Method: POST
Request Body:
{
"requests": [
{
"id": "1",
"method": "GET",
"url": "/me/contacts/firstId"
},
{
"id": "2",
"method": "GET",
"url": "/me/contacts/secondId"
}
]
}
Graph will send a response such as:
{
"responses": [
{
"id": "1",
"status": 200,
"headers": {
...
},
"body": {
...
}
},
{
"id": "2",
"status": 200,
"headers": {
...
},
"body": {
...
}
}
]
}
Make sure, that you check for the id of the request, since requests may not be returned in order, in which you sent them to Graph. The Microsoft documentation on batch processing provides more information: here.

Related

Microsoft Graph - Education user batch request not returning a value property

Running batch requests against most Microsoft Graph API endpoints returns a object with a value property like this:
{
"id": "2",
"status": 200,
"headers": {
"Cache-Control": "no-cache",
"x-ms-resource-unit": "1",
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
},
"body": {
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(id,displayName,student,teacher)",
"value": [
{
"id": "ebe6297c-1f76-484e-9616-5e8e6be6098e",
"displayName": "Adele Vance"
}
]
}
},
However running a batch request against /education/user/{userId} gives me:
{
"id": "1",
"status": 200,
"headers": {
"Cache-Control": "no-cache",
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8"
},
"body": {
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#education/users(id,displayName,student,teacher)/$entity",
"id": "ebe6297c-1f76-484e-9616-5e8e6be6098e",
"displayName": "Adele Vance"
}
}
Without any value property.
This looks like a bug. Not sure how to proceed.
Best regards,
Oskar
It depends on the endpoint you are calling in batch request.
For endpoints returning a collection, the batch response contains "value": [{..},..] in body...collection of objects.
For endpoints (like your endpoint GET /education/users/{id} that return single object, the batch response contains the object.

Graph Pagination in Logic Apps

I'm trying to fetch all users from a specific group via an HTTP connector, a registered app, and Microsoft Graph.
The registered app has Directory.Read.All permissions.
My idea is that I'm calling the nextLink as long as it's there while appending all of the fetched users' userPrincipalName to an array eventually filling the array with all users of the group.
My Logic App looks like this:
Unfortunately, I'm just 1 reputation short of posting images, please forgive. The 3 links should provide an overview of the structure of my app.
First, nextLink is initialized to the first Graph API endpoint. This variable is set to the current nextLink through each iteration of the until loop.
Second, For the purpose of this exercise, I only get the top 5. I know there are only 9 users:
Lastly, I call the union method on the "users" array that I initialized earlier and the "value" array from the HTTP get method, to get one single array consisting of all users:
The issue is that the HTTP action always returns the same top 5 users. I've checked that the nextLink provided in the first HTTP GET call to Graph, is correct by copying it from the Runs history and pasting it into Microsoft Graph Explorer and there the next 4 users are correctly returned.
I also made sure that, for each iteration in the until loop, I call the Graph API with the nextLink from the previous iteration as expected.
The nextLink returned inside of the Logic App is exactly the same when I test it in Graph Explorer, but the same nextLink returns 2 different results when called from Graph Explorer and inside my Logic App.
Why is the result always the same top 5 users and not the next 4 users as expected?
If not sure about the reason why you will get this issue, but based on your requirement, I did a sample below:
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "GetGroupUrl",
"type": "string",
"value": "https://graph.microsoft.com/v1.0/groups/<your group id>/members?$select=userPrincipalName&$top=5"
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Initialize_variable_2": {
"inputs": {
"variables": [
{
"name": "users",
"type": "array"
}
]
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Until": {
"actions": {
"Compose": {
"inputs": "#union(variables('users'),body('HTTP')['value'])",
"runAfter": {
"HTTP": [
"Succeeded"
]
},
"type": "Compose"
},
"HTTP": {
"inputs": {
"authentication": {
"audience": "https://graph.microsoft.com",
"clientId": "<app id>",
"secret": "<app secret>",
"tenant": "<your secret>",
"type": "ActiveDirectoryOAuth"
},
"method": "GET",
"uri": "#variables('GetGroupUrl')"
},
"runAfter": {},
"type": "Http"
},
"Set_variable": {
"inputs": {
"name": "GetGroupUrl",
"value": "#{if(equals(body('HTTP')?['#odata.nextLink'], null),null,body('HTTP')['#odata.nextLink'])}"
},
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"expression": "#equals(variables('GetGroupUrl'), '')",
"limit": {
"count": 60,
"timeout": "PT1H"
},
"runAfter": {
"Initialize_variable_2": [
"Succeeded"
]
},
"type": "Until"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"manual": {
"inputs": {
"method": "GET",
"schema": {
"properties": {
"text": {
"type": "string"
}
},
"type": "object"
}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}
You can just replace the params with your own and paste it into your logic app code view and test it .
It works for me, as you can see , each request results are different :
Hope it helps .
This issue solved by OP self, this issue is due to queries in request URL , copy OP's comment as an answer :
After fiddling a bit more around with what each of you providing I
found a solution. It seems that when the query arguments are passed to
the HTTP GET outside of the endpoint itself (meaning in the "queries"
field inside of the block) it seems to keep overriding the nextLink.
When writing the endpoint URL out entirely with the odata parameters,
it works as intended.

How fetch "webParts" from site pages

I am trying to fetch Pages from Sharepoint sites using graph API.
But when we make GET request with
https://graph.microsoft.com/beta/sites/{site-id}/pages/{page-id}
the response consists of webParts which only have type and data.
Inside data we have an id(which same as type) and an instanceId that is unique for every webPart.
Sample webPart:
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"id": "d1d91016-032f-456d-98a4-721247c305e8",
"instanceId": "c54a74ef-86c1-44aa-9ba4-802e6841e3a7"
}
My goal is to fetch webPages with complete details and then backup them to a local drive in any format.
The documentation of graph API shows that the responce would consist of complete details for the webPart, but it is not so.
Documentation link: https://learn.microsoft.com/en-us/graph/api/sitepage-get?view=graph-rest-beta&tabs=http
Sample request URL:
https://graph.microsoft.com/beta/sites/m365x214355.sharepoint.com,c1e5444e-12d8-43d3-96b1-f2f66559ef58,b181bdf0-9680-4988-81f7-a24aee4afd6a/pages
Webpart repsonse:
"webParts": [
{
"type": "rte",
"data": {
"innerHTML": "<p>Take a look at the team behind delivering amazing fashion events for Contoso.</p><p>Find out how the team uses the latest technology to plan amazing fashion shows and gather customer feedback for future events.</p><p>Meet the people behind Contoso's events, learn how to plan your own event, and find the necessary resources to run highly successful fashion shows, premiers, and extravaganzas!</p>"
}
},
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"id": "d1d91016-032f-456d-98a4-721247c305e8",
"instanceId": "c54a74ef-86c1-44aa-9ba4-802e6841e3a7"
}
},
{
"type": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"data": {
"id": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"instanceId": "75ccfeba-ad6c-416d-a859-4a6b114e156e"
}
},
{
"type": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"data": {
"id": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"instanceId": "f04e02fb-45e6-4e74-9f46-0c8d90e7fb8d"
}
},
{
"type": "275c0095-a77e-4f6d-a2a0-6a7626911518",
"data": {
"id": "275c0095-a77e-4f6d-a2a0-6a7626911518",
"instanceId": "c1a222b0-624e-4e30-b544-d2a67e8e1112"
}
}
Expected Response format:
"webParts": [
{
"type": "rte",
"data": {
"innerHTML": "<p>Here are the team's upcoming events:</p>"
}
},
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"title": "Events",
"description": "Display upcoming events",
"serverProcessedContent": {
"htmlStrings": {},
"searchablePlainTexts": {
"title": ""
},
"imageSources": {},
"links": {
"baseUrl": "https://www.contoso.com/sites/Engineering"
},
"componentDependencies": {
"layoutComponentId": "8ac0c53c-e8d0-4e3e-87d0-7449eb0d4027"
}
},
"dataVersion": "1.0",
"properties": {
"selectedListId": "032e08ab-89b0-4d8f-bc10-73094233615c",
"selectedCategory": "",
"dateRangeOption": 0,
"startDate": "",
"endDate": "",
"isOnSeeAllPage": false,
"layoutId": "FilmStrip",
"dataProviderId": "Event",
"webId": "0764c419-1ecc-4126-ba32-0c25ae0fffe8",
"siteId": "6b4ffc7a-cfc2-4a76-903a-1cc3686dee23"
}
}
}
]
I want webParts in the format as per documentation.
If the instanceId is unique then there might be some reference table to match these instanceIds and fetch the detailed webParts structure.

Microsoft graph batch inserting new task and updating details

Current steps for creating task are
POST /planner/tasks
GET /planner/tasks/{id from post call}/details
PATCH /planner/tasks/{id from post call}/details
If-Match: {etag from get call}
but I want to batch three steps in single call using https://developer.microsoft.com/en-us/graph/docs/concepts/json_batching
And according to odata v4 references http://docs.oasis-open.org/odata/odata-json-format/v4.01/csprd02/odata-json-format-v4.01-csprd02.html#sec_ReferencingNewEntities we can refer entities in same batch call using ${id of other request}
{
"requests": [
{
"id": "task",
"url": "/planner/tasks",
"body": {
"title": "asff",
"appliedCategories": {
"category5": true
},
"planId": "mSV7ODf3g0iTJrUtsNcvHZYAB-ZW",
"bucketId": "WFN6kxMykE-4xxqLUh1uS5YALCWq",
"assignments": {
"4393baf8-8a52-4164-bf93-b1cba5130329": {
"#odata.type": "#microsoft.graph.plannerAssignment",
"orderHint": " !"
}
},
"dueDateTime": "2018-04-23T18:30:00.000Z"
},
"method": "POST",
"headers": {
"Content-Type": "application/json"
}
},
{
"id": "getDetail",
"method": "GET",
"dependsOn": [
"task"
],
"url": "/planner/tasks/$task/details"
},
{
"id": "patchDetail",
"dependsOn": [
"getDetail"
],
"url": "/planner/tasks/$task/details",
"method": "PATCH",
"headers": {
"Content-Type": "application/json",
"if-match": "$getDetail"
},
"body": {
"description": "gwrthbetrhnety"
}
}
}
]
}
but Get details call is failing with error
{
"id": "getDetail",
"status": 400,
"body": {
"error": {
"code": "BadRequest",
"message": "The request URI is not valid. Since the segment 'tasks' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource.",
"innerError": {
"request-id": "a46ce528-993f-4cff-865e-98b2b98d5f23",
"date": "2018-04-17T10:38:29"
}
}
}
}
What I'm doing wrong here
I believe what is missing is the URI (should be POST https://graph.microsoft.com/v1.0/$batch instead of POST /planner/tasks) and "id" field has to be numeric. Check out MS documentation:
https://learn.microsoft.com/en-us/graph/json-batching?context=graph%2Fapi%2F1.0&view=graph-rest-1.0
Here is an example of combining POST and GET in a batch call

Twitter ads API "GET /1/stats/accounts/:account_id" unauthorized access

I am using postman APP for accessing GET request through TWITTER API. Though I am able to generate output through all other GET and POST request through OAUTH 1.0. But when I am sending the request through "GET /1/stats/accounts/:account_id" method, its generating the following error.
{
"errors": [
{
"code": "UNAUTHORIZED_ACCESS",
"message": "This request is not properly authenticated"
}
],
"request": {
"params": {}
}
}
I am using the following request : "https://ads-api.twitter.com/1/stats/accounts/:18ce53yh9sw?entity_ids=88hjg&entity=CAMPAIGN&end_time=2017-05-14T17:00:00Z&granularity=HOUR&metric_groups=BILLING&placement=ALL_ON_TWITTER&start_time=2017-05-05T15:00:00Z"
This is the most important GET request for me to get the campaign level data. Any other way around may be helpful.
UPDATE:
The following request is working for https://ads-api.twitter.com/1/accounts/:account_id
{
"request": {
"params": {}
},
"data": [
{
"name": "Wadi.com",
"business_name": null,
"timezone": "Asia/Riyadh",
"timezone_switch_at": "2013-05-21T21:00:00Z",
"id": "18ce53yh9sw",
"created_at": "2015-03-12T07:33:09Z",
"salt": "0f034423fa35f95e8efc844a25c4d7a3",
"updated_at": "2017-05-17T06:03:58Z",
"business_id": null,
"approval_status": "ACCEPTED",
"deleted": false
}
],
"data_type": "account",
"total_count": 1,
"next_cursor": null
}
Regards
Shree Kant

Resources