dsp-api
dsp-api copied to clipboard
Generate client code from ontologies
The basic idea is to generate client code in different programming languages (at minimum, TypeScript and Python) that makes it easier to work with the Knora APIs. This code could be generated from the Knora ontologies and from project-specific ontologies, so it could be automatically updated when those ontologies change.
Reading data
Use case 1: admin API client code
Given the class knora-base:User, generate code in Python, TypeScript, etc., that can get a user from the admin API and return a User object in the target language. Would have methods like:
getUsername: String(because ofowl:cardinality 1on propertyusername)getIsInGroup: Set[IRI](because ofowl:minCardinality 0on propertyisInGroup)
There would be some kind of factory method that would get User objects given their IDs. This method would know which API route to use and what to submit to it. This would be defined in some machine-readable file that the code generator would read.
Use case 2: client code for a project-specific ontology
Similar to (1), but for a project-specific ontology. For example, given incunabula:book, there would be a class called Book with methods like:
getTitle: Set[TextValue](because ofowl:minCardinality 1on propertytitle)getPubdate: Option[DateValue](because ofowl:maxCardinality 1on propertypubdate)
Use case 3: generic client code for project-specific data
Here there would be a Resource class with methods like:
getResourceProperties: Set[IRI]: returns the set of property IRIs that are subproperties ofknora-api:resourceProperty(and therefore have Knora values), by querying the relevant ontologygetLinkProperties: Set[IRI]getPropertyValues(propertyIri): Set[Value]
Updating data
These classes could also have set methods or constructors (whatever makes sense in the target language) for creating/updating data in Knora.
This is just a sketch of an idea, what do you all think?
@subotic @andreas-aeschlimann @kilchenmann @flavens @tobiasschweizer @lrosenth @gfoo @loicjaouen @mrivoal
An another way is to have a ORM-like library, a proof of concept with Knora here. It is only based on gravsearch BUT it does not update data.
@gfoo That looks very cool, thanks.
As a first step, I'm going to try to generate this:
https://github.com/dhlab-basel/knora-api-js-lib/blob/develop/andreas/src/models/admin/user.ts
funny enough, we also have a project that is related (client object model to make " it easier to work with the Knora APIs"):
https://github.com/LaDHUL/KnoraMVC
We have the responsibility to maintain it as long as some projects use it, which is the case for now.
It might be a guinea-pig candidate to your project.
Discussion with @subotic:
The ontology definition of a class is not going to be sufficient to generate client API code, because we need some information that is specific to an API operation, not just to a class. In particular, some classes (like TextValue) have several optional properties. Some of these properties are used in some API operations and not in others.
For example, when you receive a LinkValue, it has the property linkValueHasTarget, with an embedded target resource. But when you submit a LinkValue, you submit the property linkValueHasTargetIri, with just the IRI of the target resource.
Another example: in the knora-admin ontology, a User has the property isInProject. When you request a User, you get it back with embedded project objects. But when you create a User, you don't submit project objects with the POST request.
So we need a DSL for describing API operations. The description of each operation should specify the classes and properties that are actually used in that operation, and whether each property object is an IRI or an embedded class instance.
We think this could best be done in Scala, as a data structure of case classes. These objects could be used both for code generation and for documentation generation.
@andreas-aeschlimann please see the comment above.
How would results of Gravsearch queries be handled? The client may not want to have all of a resource's properties although some of them could be required in the ontology (cardinality 1).
For example, when you receive a LinkValue, it has the property linkValueHasTarget, with an embedded target resource. But when you submit a LinkValue, you submit the property linkValueHasTargetIri, with just the IRI of the target resource.
With Gravsearch, you could have several nested resources and specifiy the properties you want to be returned.
How would results of Gravsearch queries be handled?
After talking with @andreas-aeschlimann about this PR yesterday, it seems that the simplest solution would be not to enforce cardinalities in the client library. The client library would just submit whatever the client code gives it, and would parse whatever it receives from Knora.
and would parse whatever it receives from Knora
https://github.com/dhlab-basel/Knora-ui/blob/master/projects/knora/core/src/lib/services/v2/convert-jsonld.ts does this in the current implementation of Knora-ui.
However, in a template we want to have an idea of what we are dealing with. In BEOL, we use a mapping to achieve that:
https://github.com/dhlab-basel/beol/blob/fef23318a58fb502cab4677161431df95f4dfff0/src/app/resource/letter/letter.component.ts#L22-L43
Initial implementation in #1259, work continuing in #1392.