Getting some data from Microsoft Graph unified OData endpoint - odata

How to count number of items in EntitySet of MicrosoftGraph, for example 'users' or 'groups'? I tried:
https://graph.microsoft.com/v1.0/users?$count
Returns: lists all users
https://graph.microsoft.com/v1.0/users/$count
Returns:
{ "error": { "code": "Request_BadRequest", "message": "Unexpected segment Edm.Int32.", } }
Also in Annotations of target "microsoft.graph.directoryObject" which are those EntitySets based on I see that it is Selectable=false, Countable=false ...
Will $skip be ever available on 'users' or other toplevel EntitySet items ( https://graph.microsoft.com/v1.0/groups?$skip=5 ) ? It is available on other items ( https://graph.microsoft.com/v1.0/me/contacts?$skip=5 ). I know about $skipToken, but it is not the same.
Can I find somewhere in the $metadata if property is sortable? For example user.displayName is sortable, but user.mail or user.givenName are not. This would be handy in the $metadata. Is there plan to introduce this into $metadata?
OrderBy DESC in this formula https://graph.microsoft.com/v1.0/users?$orderBy=displayName%20desc is ignored, it shows items ordered ASC, am I doing something wrong?

Not much help I know, but if you do an API call that gets a Collection you can get a count using the second form you gave in the first question. Eg:
https://graph.microsoft.com/v1.0/users/<id>/events/$count
returns the count (6 in my case, and not in JSON - the returned data is actually "\x{ef}\x{bb}\x{bf}6" (in Perl formatting)). If we use the ? as the last separator (which is what http://graph.microsoft.io/en-us/docs/overview/query_parameters seems to indicate we should) with this URL:
https://graph.microsoft.com/v1.0/users/<id>/events?$count
I just get the list of events with no count as you do.
So that seems to indicate two things to me:
a) The $count doesn't appear to work as a query parameter, despite the documentation and the OData standards saying it should,
and
b) There seems to be a bug in the API for handling EntitySets which isn't there for Collections.
Sorry I can't be of more help, but its another data point at least (I just came unstuck with the same thing which is why I noticed this StackOverflow post!)

Ad 1. https://graph.microsoft.com/v1.0/users/$count is the correct OData syntax (http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-errata02-os-part2-url-conventions-complete.html#_Toc406398087), but as indicated in the metadata directoryObject collections are not currently countable. ODataV4 also allows $count in query parameters (http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-errata02-os-part2-url-conventions-complete.html#_Toc406398166), but then it should be specified with true or false value (e.g. https://graph.microsoft.com/v1.0/me/events?$count=true) and the response will include both the collection and its count in the #odata.count property. This is again not supported for directoryObject collections.
Ad 2. There is no plan right now to support $skip for directoryObject collections.
Ad 3. Yes, we plan to indicate which properties are sortable by in metadata using the SortRestrictions annotation defined in the OData capabilities vocabulary (http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/vocabularies/Org.OData.Capabilities.V1.xml)
Ad 4. Your request is correct, but we only support sorting users by displayName in the ascending order.

Related

Graph Bookings API - List appointment returning empty customers array

When invoking either
GET /solutions/bookingBusinesses/{id}/calendarView
or
GET /solutions/bookingBusinesses/{id}/appointments
the returned bookingAppointment object has an empty customer array. However the customers appear in the UI. Any idea why this may be the case?
Looks like a bug in Graph API.
According to the documentation the customers property is optional. Sometimes you have to specify optional property in $select statement.
GET solutions/bookingBusinesses/{id}/calendarView?start=2018-04-30T00:00:00Z&end=2018-05-10T00:00:00Z&$select=customers
Another option is trying beta version instead of v1.0
GET beta/solutions/bookingBusinesses/{id}/calendarView?start=2018-04-30T00:00:00Z&end=2018-05-10T00:00:00Z

Acumatica OpenAPI can not search stock item by barcode in cross references

I'm trying to use OpenAPI to fetch data from Acumatica.The filter is barcode in CROSS-REFERENCEEimage.
It's unable to fetch data(before change) because
"The parent value for a property access of a property 'AlternateID' is not a single value. Property access can only be applied to a single value."
I did some research and find a same question(OData $filter with items in a $expand).
I changed(after change) my request but still get
"exceptionMessage": "The method or operation is not implemented." error.
I really know nothing about OData and C#.I use JAVA/NODEJS to fetch data. Can someone give me any suggestion? Thanks a lot.
You can't do it this way.
Acumatica doesn't support filtration over the detail records.
Instead, you can create a new GI that will contain the information from the Inventory Item and corresponding Alternate IDs and request the records from that GI.

Changing location of $top clause in OData query changes results when Querying MSAX7

I have an ODATA query that pulls the first record from the Dynamics AX table and ignores the $filter clause when the $top parameter is the first parameter. However, it pulls the correct record for the $filter clause when the $top parameter is at the end of the query.
Question: How do I make the OData server honor the full query no matter where the $top parameter is placed?
the following two cases return identical results:
Case 1: https://url/data/Users?$top=1
{
"#odata.context":"https://url/data/$metadata#Users","value":[
{
"#odata.etag":"W/\"J5zEx4NDg33OD2YyM4TEs5NTY6zNz7E0ND7U3Nic=\"",
"Id":"first_user_in_the_table",
"Alias":"first_user_in_the_table#domain.com",
"Name":"first_user_in_the_table"
}
]
}
Case 2: https://url/data/Users?$top=1&$filter=Alias%20eq%20%27specific_user#domain.com%27
{
"#odata.context":"https://url/data/$metadata#Users","value":[
{
"#odata.etag":"W/\"J5zEx4NDg33OD2YyM4TEs5NTY6zNz7E0ND7U3Nic=\"",
"Id":"first_user_in_the_table",
"Alias":"first_user_in_the_table#domain.com",
"Name":"first_user_in_the_table"
}
]
}
However, when I move the $top parameter to the end of the query string I get the correct result.
Case 3: https://url/data/Users?$filter=Alias%20eq%20%27specific_user#domain.com%27&$top=1
{
"#odata.context":"https://url/data/$metadata#Users","value":[
{
"#odata.etag":"W/\"Jz3kz4Nj5g2N6zcz7MCw81Nj9M3M2TU3w4NT4c54Jw==\"",
"Id":"specific_user",
"Alias":"specific_user#domain.com",
"Name":"The Specific User I Actually Want"
}
]
}
As far as I understand the OData specification, this is incorrect behavior. I base this on 11.2 Requesting Data which states that the $top query option should be evaluated last and after the $filter query option. Also section 2. Query Options of the OData ABNF construction rules seems to indicate that the query options may appear in any order in the URL.
This indicates that this particular behavior may have been incorrectly implemented. You will probably not be able to solve this short of implementing a custom service that wraps the existing one to reorder the query options as needed. I would also assume that this impacts the behavior of all Odata services.
I suggest you create a support request with Microsoft so they can adress this.

How to correctly query OData with filter in nested type based on property from parent type?

I am getting a dynamic value (_FilterDate) on the parent type that I want to use as a filter for the nested type /Trips but can't get it to work because I still get entries in the nested data that do not meet the filter. Actually, there is no difference whether I use this filter or not.
$filter=Trips/all(d:d/EndDate ge _FilterDate)
I also tried this:
$expand=Trips($filter=EndDate ge $it/_FilterDate)
but got the error: "Could not find a property named '_FilterDate' on type 'Default.Trips'."
So I'm wondering how to get the syntax right and thus kindly ask for help.
Example portion:
"value": [
{
"_FilterCompany": "YES",
"_FilterLocation": "YES",
"_FilterDate": "2020-01-08",
"Trips": [
{
"StartDate": "2019-06-24",
"EndDate": "2019-06-28",
},
{
"StartDate": "2020-02-07",
"EndDate": "2020-02-07",
}
]
}
There are two issues going on here:
this response is specifically regarding the OData v4 specification and the .Net ODataLib implementation.
You have correctly identified that when filtering results based on a nested collection you you must separately apply the filter within that collection if you want the fitler to apply to the items within that collection as well.
This is because the root level $filter criteria only affects the selection of the root items, think of it as if the $expand operator is applied after the $filter has identified the top level of row the return, $expand is simply executed as a Linq Include statement.
In your second attempt, $it references the instance of Trips, which is a known bug/by design, according to the spec it is expected to work the way you have implemented it:
5.1.1.6.4 $it
Example 82: customers along with their orders that shipped to the same city as the customer's address. The nested filter expression is evaluated in the context of Orders; $it allows referring to values in the outer context of Customers.
http://host/service/Customers?
$expand=Orders($filter=$it/Address/City eq ShipTo/City)
So knowing the $it is broken, the spec doc does specify a $root identifier that you might also be able to use, but in ODataLib 7.3 $root is still not supported OOTB either. There is an issue logged here: $it references the wrong resource #616
Workaround
If your Trips data type has a navigation property back to the Filter/root record, then you can use that navigation property as part of the $filter:
Assuming the navigation property is called Filter
$filter=Trips/all(d:d/EndDate ge _FilterDate)&$expand=Trips($filter=EndDate ge Filter/_FilterDate)
If your Trips type does not have this navigation link back to the parent record then you are stuck at this stage with these two workarounds:
Create a Function on the controller to return this filtered data specifically, as this would be simple to evaluate as a Linq query in the server-side.
Accept that the server will return extra rows in the Trips collections, and apply the filter over the results in the client-side.

Handling of Non-Existing Properties in Microsoft Graph

This is from the category "unexpected behavior" - take the following query (you can paste it in Graph Explorer):
https://graph.microsoft.com/v1.0/users?$filter=idc eq 'test'
This returns status code 400 and "Property 'idc' does not exist as a declared property or extension property." Which is a sensible and understandable response.
Now, if try to $select this property:
https://graph.microsoft.com/v1.0/users?$select=idc
I get a result I totally don't expect:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(idc)",
"#odata.nextLink": "https://graph.microsoft.com/v1.0/users?$select=idc&$skiptoken=cut",
"value": [
{},
{},
...
{}
]
}
(a list of empty objects; asking for a single user with that invalid property name returns me an emtpy response).
So my question is - why does $filter error out and $select does not? Would there be a way to force $select to error out too? (eg I am using the /beta endpoint and a property name changes - I want my code to fail to find out)
Sorry for the late answer. We had a discussion on this and would love to get some of your thoughts (and the thoughts of other developers). We don't have a clear answer on this yet.
There are 2 schools of thought here:
Make $select and $filter behave consistently when dealing with properties that don't exist.
It's OK for these to differ in behavior, since the caller’s intent when specifying $select is likely different than that of $filter. The service cannot ignore a property specified in $filter because it completely changes the set of objects that are returned. However, $select does not change the set of objects but only drops the properties that are not available. Hence $select and $filter do not need to be consistent.
Thoughts?
Hope this helps,

Resources