Microsoft Graph present #nextlink even with $top=1? - microsoft-graph-api

We are querying data using MS Graph OData API, but I found msGraph presents nextlink unexpectedly.
For example, even though I intend to query only one record by specifying $top=1:
https://graph.microsoft.com/v1.0/users?$top=1
in the response there is a #nextlink, which leads to another query to this link by our tool.
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
"**#odata.nextLink**": "https://graph.microsoft.com/v1.0/users?$top=1&$skiptoken=X%2744537074020001000000223A4164616D73404D333635783231343335352E6F6E6D6963726F736F66742E636F6D29557365725F36653762373638652D303765322D343831302D383435392D343835663834663866323034B900000000000000000000%27",
"value": [
{
"id": "6e7b768e-07e2-4810-8459-485f84f8f204",
"businessPhones": [],
"displayName": "Conf Room Adams",
"givenName": null,
"jobTitle": null,
"mail": "Adams#M365x214355.onmicrosoft.com",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": null,
"userPrincipalName": "Adams#M365x214355.onmicrosoft.com"
}
]
}
One can reproduce it in graph-explorer
Is it working as expected?
I think there should be no nextlink since I only want one record. Is this a bug?

Using $top=x doesn't actually mean
I want you to show me only first x record(s) and ignore the rest
Its role (based on the query parameter docs) is:
Sets the page size of results.
What you saw is the expected outcome, as using $top is one of the cases where paging is used:
Some queries against Microsoft Graph return multiple pages of data either due to server-side paging or due to the use of the $top query parameter to specifically limit the page size in a request.
And further:
When a result set spans multiple pages, Microsoft Graph returns an #odata.nextLink property in the response that contains a URL to the next page of results.
Which precisely answers your question. If you want. feel free to read more about paging here.
Also remember that while using $top query parameter it's a good practice to remember about sorting (source: OData official documentation).

Related

/beta MS Graph /sites/lists lastModifiedDateTime is wrong?

Using MS Graph API /beta endpoint to figure out if the list has been updated/changed.
Used the following query first:
https://graph.microsoft.com/beta/sites/xxxxx.sharepoint.com:/sites/xxxxx?$expand=lists(select=id, name, system, lastModifiedDateTime)
And did get the following date:
"lastModifiedDateTime": "2018-10-08T10:23:37Z",
But when going against the items and see the dates on the latest item with the following query:
https://graph.microsoft.com/beta/sites/xxxxx.sharepoint.com,92af4fbc-04bc-46d8-9c78-f63832fbf48a,1b59d85a-41bd-4498-a64c-17bd13069d90/lists/b9c39323-076a-4ae7-942b-1d0060a6b352/items
you can see the dates:
"createdDateTime": "2018-10-08T10:23:37Z"
"lastModifiedDateTime": "2018-10-08T10:29:14Z",
You can see that lastModifiedDateTime property on the list looks like actually lastCreatedDateTime?
Best Regards,
Kim
edit:
First graph request gets the SitePages list and its lastModifiedDateTime:
{
"id": "b9c39323-076a-4ae7-942b-1d0060a6b352",
"lastModifiedDateTime": "2018-10-08T10:23:37Z",
"name": "SitePages",
"system": {}
},
But if we then look at the items of the list, we can see that it has an item with a higher lastModifiedDateTime (second graph request):
"createdDateTime": "2018-10-08T10:23:37Z",
"eTag": "\"27e03a98-9321-4586-8ef1-0b5323c26730,6\"",
"id": "8",
"lastModifiedDateTime": "2018-10-08T10:29:14Z",
We can also see that the createdDateTime of the listitem is the same as the list lastModifiedDateTime. Looks like a bug in the api to mee. The date in the first request should be "2018-10-08T10:29:14Z". Dont you agree?
As your description, I assume you want to know why the LastModifyDateTime is different.
Base on my test, your first link is to get the lastModifyDateTime of the special site,
but your second link is about the items of the b9c39....
We can use the MS Graph Explore to check whether this two site has some differences.
Indeed, it appears to be a bug, for List resource lastModifiedDateTime property returns invalid value, it seems to be mapped to the last list item date and time when the item was created (ListItem.createdDateTime)
It could also be confirmed as a bug using the following endpoints (in both examples a valid lastModifiedDateTime value is returned):
https://graph.microsoft.com/beta/sites/{site-id}/lists/{list-id}/drive/root?select=lastModifiedDateTime
https://tenant.sharepoint.com/_api/web/lists/getbyid({list-id})?$select=LastItemModifiedDate
Meanwhile as a workaround the following solution could be considered to enumerate site lists:
https://graph.microsoft.com/beta/sites/{site-id}/drives?expand=root(select=lastModifiedDateTime)
where root/lastModifiedDateTime returns a valid value
Limitation: Only returns document libraries

Using filter on /me/joinedTeams not working

I'm implementing a search for a user's joined Teams unsing Microsoft Graph. The idea is to make a call to /beta/me/joinedTeams and use a ?$filter=startswith(description,'searchterm') filter.
So for example when I try the request https://graph.microsoft.com/beta/me/joinedTeams?$filter=startswith(description,'Business') in the Microsoft Graph Explorer it ignores the filter and I get these results:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#groups",
"value": [
{
"id": "02bd9fd6-8f93-4758-87c3-1fb73740a315",
"displayName": "HR Taskforce",
"description": "Welcome to the HR Taskforce team.",
"isArchived": false
},
{
"id": "13be6971-79db-4f33-9d41-b25589ca25af",
"displayName": "Business Development",
"description": "Welcome to the BizDev team.",
"isArchived": false
},
{
"id": "8090c93e-ba7c-433e-9f39-08c7ba07c0b3",
"displayName": "X1050 Launch Team",
"description": "Welcome to the team that we've assembled to launch our product.",
"isArchived": false
}
]
}
Am I doing something wrong with my request?
Your request is right, but the joinedTeams does not support filtering or ordering results. So although we pass the filter/orderby parameter, when Microsoft Graph sees a query parameter it doesn't expect, it simply ignores the unknown filter/orderby parameter and returns an unfiltered/default-sorted result.
I have tried the api with odata query parameters for trial O365 account and real account.
https://developer.microsoft.com/en-us/graph/docs/concepts/query_parameters
Not all parameters are supported across all Microsoft Graph APIs, and
support might differ significantly between the v1.0 and beta
endpoints.
The only suggestion for you is to vote up the existing feature request in User Voice or submit a new one.
Thanks for pointing this out. As Seiya points out, /me/joinedTeams does not support the OData query parameters. The documentation suggested otherwise, I've made a doc fix that should propagate in the next day or two.

Microsoft Graph Api: Filter by GUID value

I am trying to use Microsoft Graph Api to get the details of a specific user.
I have a problem that can be demonstrated using the Graph Explorer: https://developer.microsoft.com/en-us/graph/graph-explorer
If I run this query:
https://graph.microsoft.com/v1.0/users
I get a list of users, including their ID.
I know I can get the details of just one user by appending the id to the url. For example, this query:
https://graph.microsoft.com/v1.0/users/f71f1f74-bf1f-4e6b-b266-c777ea76e2c7
Results in the details of one specific user.
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"id": "f71f1f74-bf1f-4e6b-b266-c777ea76e2c7",
"businessPhones": [],
"displayName": "CIE Administrator",
"givenName": "CIE",
"jobTitle": null,
"mail": "admin#CIE493742.onmicrosoft.com",
"mobilePhone": "+1 3528700812",
"officeLocation": null,
"preferredLanguage": "en-US",
"surname": "Administrator",
"userPrincipalName": "admin#CIE493742.onmicrosoft.com"
}
However, in my case, it would be easier to apply a $filter query on the id field.
Here is what I have tried, and the errors I get:
Attempt One
.../users?$filter=id eq f71f1f74-bf1f-4e6b-b266-c777ea76e2c7
Returns the following message:
A binary operator with incompatible types was detected. Found operand types 'Edm.String' and 'Edm.Guid' for operator kind 'Equal'.
Attempt Two
..../users/$filter=id eq guid'f71f1f74-bf1f-4e6b-b266-c777ea76e2c7'
Returns the following message:
Unrecognized 'Edm.String' literal 'guid'f71f1f74-bf1f-4e6b-b266-c777ea76e2c7'' at '6' in 'id eq guid'f71f1f74-bf1f-4e6b-b266-c777ea76e2c7''.
Finally figured it out.
Simply wrap the guid in single quotes, with no other annotations.
https://graph.microsoft.com/v1.0/users?$filter=id eq 'f71f1f74-bf1f-4e6b-b266-c777ea76e2c7'

Unable to create course via api

I am trying to create a course in a semester through the api in valence d2l. I keep getting a 404 not found error, both in my program and in the "getting started" application. The call I am making is to /d2l/api/lp/1.0/courses/ using post. I pass the following JSON object along with it:
{
"Name": "COMM291 - Test A",
"Code": "C-COMM291",
"Path": "/enforced/C-COMM291/",
"CourseTemplateId": 20992,
"SemesterId": 20993,
"StartDate": "2013-08-22T19:41:14.0983532Z",
"EndDate": "2013-08-27T19:41:14.0993532Z",
"LocaleId": 4105,
"ForceLocale": false,
"ShowAddressBook": false
}
I have also tried passing null for the fields that say they accept null values, but no luck. The course template and the semester ID are correct - I have tripled checked that they exist, I am enrolled in them and I am using the correct ID numbers.
Try reducing the precision in your start and end dates to three decimals after the final point (e.g., "2013-08-22T19:41:14.0983532Z" becomes "2013-08-22T19:41:14.098Z").
If your org is configured to automatically enforce, and generate, paths for course offerings, then you should not provide one in your CreateCourseOffering block at all. The following structure works on our test instance: notice the empty string for path (shouldn't be null, but an empty string, I believe):
{ "Name": "Extensibility 104",
"Code": "EXT-104",
"Path": "",
"CourseTemplateId": 8082,
"SemesterId": 6984,
"StartDate": "2013-09-01T19:41:14.098Z",
"EndDate": "2013-12-27T19:41:14.098Z",
"LocaleId": 1,
"ForceLocale": false,
"ShowAddressBook": false }
The other thing to note is that if your CreateCourse form doesn't have a form element to provide a Semester ID, then your API call should pass null for that property.
I found that part of my problem was with the call if I change it to /d2l/api/lp/1.3/courses/ instead of 1.0 it works, (1.0 will work but it seems that you can only pass null for the semester).
The dates were also picky and did prefer milliseconds to only 3 decimal places.
Then passing null for LocaleId also helped.

Restkit: How to get and map data from multiple source

I'm currently working on iOS Application with RestKit 0.20 to access data from Tastypie API.
And I am trying to get feeds data from URL like this
/api/v2/feed/?format=json
Then I will get array of feeds as below.
{
"meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 2
},
"objects": [
{
"id": 1,
"info": "This is my first post",
"pub_date": "2013-02-03T15:59:33.311000",
"user": "/api/v2/user/1/",
"resource_uri": "/api/v2/feed/1/"
},
{
"id": 2,
"info": "second post, yeah",
"pub_date": "2013-02-03T16:00:09.350000",
"user": "/api/v2/user/1/",
"resource_uri": "/api/v2/feed/2/"
}
]
}
if I want to fetch more data about user which Tastypie send it as url like a foreign key "user": "/api/v2/user/1/", do I have to nested call objectRequestOperation.
I'm confusing because I'm using block to callback when data is successful loaded. So is there any better way than requesting user data again for each feed after requesting feed complete.
Thank you very much :)
You have to define in the Feed resource :
user = fields.ToOneField(UserResource, full=True)
More info in the tastypie doc http://django-tastypie.readthedocs.org/en/latest/resources.html
Why Resource URIs?
Resource URIs play a heavy role in how Tastypie delivers data. This can seem very different from other solutions which simply inline related data. Though Tastypie can inline data like that (using full=True on the field with the relation), the default is to provide URIs.
URIs are useful because it results in smaller payloads, letting you fetch only the data that is important to you. You can imagine an instance where an object has thousands of related items that you may not be interested in.
URIs are also very cache-able, because the data at each endpoint is less likely to frequently change.
And URIs encourage proper use of each endpoint to display the data that endpoint covers.
Ideology aside, you should use whatever suits you. If you prefer fewer requests & fewer endpoints, use of full=True is available, but be aware of the consequences of each approach.

Resources