oData v4 - ordering outer entity on property in related one-to-many entities - asp.net

I have an oData model with a couple of one-to-many relationship, say person->addresses and person->driving-licences. I would like to be able to sort the result set based on properties in the address entity and driving licence entity. As there could be more than one address, I would initially select a single item from the addresses set, based on a property called IsPrimary. As there could be more that one driving licence, I would select the 'UK' driving licence. Is this possible?
I was hoping I could do something like:
/people?$expand=addresses($filter=isPrimary eq true),drivinglicences($filter=country eq 'UK')&$orderby=addresses/postcode,drivinglicences/active
Unfortunately I get the following error:
"The query specified in the URI is not valid. The parent value for a property access of a property 'isPrimary' is not a single value. Property access can only be applied to a single value."
Does anyone know if what I'm trying to do is supported by the spec? Or whether it is an issue with my query? Or whether it is an issue with the .NET library.
I'm using:
Microsoft.AspNet.OData - 7.2.3
Many Thanks.

What you see here is by design, or rather not supported by the specification, the error message even highlights the only type of expressions supported:
The query specified in the URI is not valid. The parent value for a property access of a property 'isPrimary' is not a single value. Property access can only be applied to a single value.
So the simplest solution is to modify the API either to include a Function bound to the people collection that applies the $filter or $order directly, or a Function that returns the data in a new shape, one that only has perhaps a singleton PrimaryAddress property. How you include driving license in this result is up to you, it could even be a parameter to the function, perhaps your people controller has a queryable function with this signature:
[EnableQuery]
public IHttpActionResult WithLicences(string countryCode)
However that is out of the scope of OPs question about specific syntax support
Although it seems like an important feature, we must remember that $select (Projection) and $filter are evaluated at different points in time, OData queries follow a similar execution sequence to SQL however the filter criteria and $orderby are evaluated separately, and the projection of the resultset is the last evaluation to be applied.
Due to $filter and $orderby being applied independently, neither concept is even aware of the other and as such neither can reference or assume to be applied before the other.
You can prove this by specifying a field in the $orderby and/or $filter that is not included in the $select, you can even reference singleton navigation fields that are not included in an $expand and the query will evaluate correctly.
The OData spec is similar to a law document, in that to properly understand and apply it we need to understand the original intent of the authors. We can get an initial understanding from the early listing of Addressing Entities
Addressing Entities describes functions that can be bound to collections or entities that return either a single entity or a collection of entities
By allowing special provision of custom functions to be applied the authors are encouraging API designers to provide natural extensions to their resource endpoints that can facilitate the execution of pre-determined queries that may be otherwise complex or problematic to express in pure OData query syntax.
In other words, we are encouraged to customise our APIs to make them easier for the end process to consume, and to guide the consuming developer to make the best use of the API, they shouldn't have to discover everything from first principals.
To achieve OPs type of query in pure SQL would still require either a nested lookup, CTE or self join... advanced syntax. In OData v4, the specification does not provide a syntax for targeting specific items within a collection for path expressions (of which $orderby derives from)
5.1.1.15 Path Expressions
Properties and navigation properties of the entity type of the set of resources that are addressed by the request URL can be used as operands or function parameters, as shown in the preceding examples.
Properties of complex properties can be used via the same syntax as in resource paths, i.e. by specifying the name of a complex property, followed by a forward slash (/) and the name of a property of the complex property, and so on,
Properties and navigation properties of entities related with a target cardinality 0..1 or 1 can be used by specifying the navigation property, followed by a forward slash (/) and the name of a property of the related entity, and so on.
If a complex property is null, or no entity is related (in case of target cardinality 0..1), its value, and the values of its components, are treated as null.
RE: I couldn't find anything explicit in the spec. :)
That is the very thing about the OData specification,the specification does not list what is not supported, only what should be supported. So by omission, if you cannot find a reference to how to do something, then that something is not required to be supported.
Introduction http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_Introduction ... This specification defines a set of recommended (but not required) rules for constructing URLs to identify the data and metadata exposed by an OData service as well as a set of reserved URL query string operators, which if accepted by an OData service, MUST be implemented as required by this document.
This has been on ongoing discussion held in may threads, recently https://stackoverflow.com/a/55324393/1690217
Many people complain that this is surely a fundamental feature of a data access platform, however it is important to respect the original intent of the OData platform and keep our APIs simple by providing customised endpoints to suit our business domain.

Related

API Platform custom IRI with value objects

I am currently trying to create a custom IRI for one of my entities in API Platform.
I know there is page in the documentation describing how to use a custom IRI (https://api-platform.com/docs/core/identifiers/), but I can't get it working.
My entity uses a value object for the id (currently used for IRI) and also for the name (should be used for IRI). But the values themself are priviate and scalar in the entity.
API Platform seems to get the information what should be used as the identifier, from my XML Doctrine mapping. I already tried to overwrite it by usung annotations, attributues and YAML definitions. Without luck.
The returned error reads:
preg_match(): Argument #2 ($subject) must be of type string
(at this point it receives the value object instead of the actual value)
best regards,
spigandromeda
I solved my problem.
To explain the solution, I have to dig a little into API Platform response generation.
API platform generates an IRI for every entity it returns (colelction and item operation)
it's using the Symfony router go generate the URI
all the necessary information can draw API Platform from different sources (YAML, XML, annotations, attributes)
the information include the identifier(s) defined for the entities resource
API Platform gets the value for the identifier via Symfony property accessor
because the property accessor is using getters before accessing private properties via reflection, it will return the VO
an ordinary VO cannot be used by the Symfony URL generator to create the URL
As I explained, I am using a VO for my Id as well. So I tried to figure out why it was working with the Id VO but not with the name VO.
Simple answer: the Id VO implemented the __toString method and the name VO didn't. So the solution was to let the name VO implement this method as well.
It was interesing to dig into the internal process of API Platform, but I also feel a little stupid :D

JSON-LD, is there any way to specify the default URI for the #id of a #type or the values of a property?

(I've already asked this on the W3/JSON mailing list, I'll try here too.)
I'm fairly new to JSON-LD, although I have significant experience with Semantic Web technologies.
I've read the guideline document (https://www.w3.org/TR/json-ld/) and I haven't get if the feature at issue is supported:
Suppose you have JSON objects of #type Person and #type Address, both having the #id property. Typical API-coming data will have values like integers or some internal, context-dependant IDs. It's pretty common to RDF-translate those values to prefix-based URIs like http://www.example.com/Person/123 or http://www.example.com/Address/xh324m44.
What I would like to do is to specify those prefixes and keep data telling #id = '123', with the value joins happening at RDF serialisation stage (the same specification would make it possible to do the opposite conversion too). Clearly, in such a use case, the prefixes depend on the #type of objects, and the #base mechanism is not enough. Moreover, it would be useful to have this mechanism available for properties too, e.g., to associate the address URI prefix to the values of the "address" JSON property.
It doesn't seem that this is currently available in JSON-LD, or am I missing something? Any plan for future extensions?
You can use #base in the context to create a URI base for values of #id, but this will not include something from #type. This sounds like something you might get by defining a URI template and using variables to expand type and id to create a URI. You can do this in a templating language and create the JSON-LD, but not directly in JSON-LD itself. Not likely to be a feature included by the language in the future, either, as it's application is pretty narrow.

Adding a callback when reading from an object in Twig

Let's say I have a basic entity called Entity which is mapped to a database table. This entity has got two properties: propertyA and propertyB.
One particularity of this entity is, although we may store whatever we want in these properties, when using the value of propertyB on a Twig template with entity.propertyB we want to systematically truncate the value to 100 characters.
Now, this is perfectly doable in several ways:
Truncate the value directly in the getPropertyB() method;
Register a Twig extension and create a dedicated filter;
Add a lifecycle callback on the entity to truncate the value before the object is actually created.
As this is strictly a display rule, and not a business rule on our entity, the second solution seems to be the best IMHO. However, it demands we apply the filter every time we need to use the value of propertyB in a template. Should an unaware developer come by, the value may not be truncated.
So my question is: is there a way to register some kind of callback, strictly restricted to the view model wrapping our entity, which would allow us to apply some filters on the fly on some of its properties ?
Since you never need to access anything beyond 100 characters, you can truncate the property in its setter. This doesn't really pollute Entity code, because this is some logic inherent to it.

Is this a valid mapping for a REST API?

I've come up with the mapping that follows while working on the REST API of a system where users are able to create and manage resources of different types.
// READ OPERATIONS
GET /objects => read collection meta
GET /objects/[id] => read single element
GET /objects/?[query] => read a number of elements
GET /objects/?all => read all elements
// CREATE / UPDATE OPERATIONS
PUT /objects => possibly create the collection and update its meta
PUT /objects/[id] => possibly create and update a single element
PUT /objects/?all => update the entire content of the collection
POST /objects => create new objects or update existing objects
PATCH /objects => partially update the collection meta
PATCH /objects/[id] => partially update a single element
PATCH /objects/?all => partially update all the elements
PATCH /objects/?[query] => partially update a number of elements
// DELETE OPERATIONS
DELETE /objects => delete the collection
DELETE /objects/[id] => delete a single element
DELETE /objects/?all => empty the collection
DELETE /objects/?[query] => delete a number of elements
Here's some more information on the system:
each resource can be either be a simple one or a collection-like one;
each resource, collection or not, has properties of its own that need to be accessed and manipulated;
the API must support bulk (not batch) operations.
I've also examined the following alternatives:
using /collection to access the collection's set of elements and /collection?meta to access the collection's own data;
using a whole new resource to access a collection's own data, such as /collections/path/to/collection.
I do not like alternative n. 1) because it feels, to me, semantically poor. By comparison, when I refer to a box I am actually referring to the box in itself and not to its content.
I do not like alternative n. 2) because a resource ends up having its own data exposed by another resource, duplicating urls and making the problem of "which url should I use" not that trivial as I'd like it to be.
Therefore, my questions:
Is the mapping I have proposed a valid, proper mapping for a REST API? Is it respectful of REST principles? I'm not asking whether it's the best mapping out there or not. I'm asking about its validity.
If not, which one of the alternatives is the better one and why?
Please excuse my english, I'm not a native speaker of the language.
I thought the API design looked OK, but then I re-read this comment of yours at the start:
where users are able to create and manage resources of different
types.
If the resources of your system are of different types, why are you exposing them with a neutral, type-less API that works only with generic objects?
The first part of RESTful API design is the identification of the nouns in your system, and those nouns should be considered strongly as candidates for exposure as URIs. I would strongly encourage you to try and get more specific than object and model the business functionality of your system with clearer URIs.
And your English is fine!
First of all, the semantics of URIs aren't relevant to REST. "RESTful URI" is almost an oxymoron. The only constraint an URI must follow to be RESTful is that it references one and only one resource.
Obviously, that doesn't mean REST URIs can be obscure. They should be as clear, intuitive and descriptive as possible, but whatever scheme you decide to use is fine, as long as its consistent. If you're so concerned with this, it means you're probably not using HATEOAS and should take a look at it.
Second, you're not considering the media types, and that's why you end up with the problem of using URIs to designate different media types. Let's say that retrieving all elements of a collection should be simply:
GET /objects
And retrieving a single element of a collection should be:
GET /objects/[id]
Now, if the client needs only the metadata for a resource, either a collection or a single element, it should specify that through the Accept header, not by going to a separate URI you point to in the documentation, or even worse, by adding query string parameters.
So, for instance, if the media type for your object is application/vnd.mycompany.myobject+json, your clients get the full object representation when using that media type in the Accept header, and get the metadata by using something like application/vnd.mycompany.myobjectmetadata+json.
I guess this probably isn't what you expected, but that's what REST is. Your documentation and design effort should be focused on your media types, not your URIs. When you use HATEOAS, URI design is irrelevant, and if you're not using HATEOAS, you're not using REST.

hashtable keys() keySet() which is better

Just curiously I am asking which is the better method to use Hashtable.keys() or Hashtable.keySet(). Any one would have been sufficient. Why have they given 2 methods with different return types. Is there any performance drawback/benefit of one over the other ?
keySet is there because
it returns a Set view of the keys contained in this Hashtable. The Set is backed by the Hashtable, so changes to the Hashtable are reflected in the Set, and vice-versa. The Set supports element removal (which removes the corresponding entry from the Hashtable), but not element addition.
And keys just returns an enumeration of the keys in this hashtable, no changes will be reflected after getting enumeration.
Besides the funcitonal difference mentioned by Rahul, Hashtable itself is an old artifact of earlier java version and retrofitted to implement Map interface.
So keySet is a later construct required by the Map interface.
Additionally, if this is new code that you are writing, you should read up the api details for this data structure on http://docs.oracle.com/javase/7/docs/api/java/util/Hashtable.html and see if you should consider the guideline and use HashMap or other later Collections instead.

Resources