dsp-api icon indicating copy to clipboard operation
dsp-api copied to clipboard

Generate client code from ontologies

Open benjamingeer opened this issue 6 years ago • 9 comments

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 of owl:cardinality 1 on property username)
  • getIsInGroup: Set[IRI] (because of owl:minCardinality 0 on property isInGroup)

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 of owl:minCardinality 1 on property title)
  • getPubdate: Option[DateValue] (because of owl:maxCardinality 1 on property pubdate)

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 of knora-api:resourceProperty (and therefore have Knora values), by querying the relevant ontology
  • getLinkProperties: 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

benjamingeer avatar Mar 18 '19 15:03 benjamingeer

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 avatar Mar 18 '19 15:03 gfoo

@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

benjamingeer avatar Mar 18 '19 17:03 benjamingeer

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.

loicjaouen avatar Apr 01 '19 22:04 loicjaouen

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.

benjamingeer avatar May 21 '19 10:05 benjamingeer

@andreas-aeschlimann please see the comment above.

benjamingeer avatar May 21 '19 12:05 benjamingeer

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.

tobiasschweizer avatar May 22 '19 16:05 tobiasschweizer

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.

benjamingeer avatar May 22 '19 16:05 benjamingeer

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

tobiasschweizer avatar May 22 '19 20:05 tobiasschweizer

Initial implementation in #1259, work continuing in #1392.

benjamingeer avatar Aug 20 '19 12:08 benjamingeer