0
votes

Situation

I am working on an OpenAPI v3 specification for an existing codebase. The approach is based on swagger-core in a jaxrs (jersey) context. The API will need to support a graph consisting of vertices (entities with properties) and edges (linking vertices, possibly having properties). For json (de)serialisation, we're relying on jackson.

The model (related to graphs) is something like:

Vertex:
  type: object
  ...
  properties:
    id:
      type: string
    ...

Edge:
  type: object
  ...
  properties:
    start:
      $ref: '#/components/schemas/Vertex'
    destination:
      $ref: '#/components/schemas/Vertex'

Issues / challenges

There are two issues:

  • Overhead: This schema (and how we're using it) would result in vertices to be repeated in the start and destination fields of edges. This is unnecessary payload which may be considerable for large vertices (may properties / large values) and many edges referencing these vertices.
  • Correctness: A more serious issue is that it may be unclear which vertex is the correct vertex. I.e. multiple instances of Vertex may occur in a request / response with the same id, but with different values. This seems error prone.

Directions of solution

In the API side, we can use @JsonIdentityInfo and @JsonIdentityReference to resolve these issues. However, it seems impossible to generate clients that work with this.

I guess the main issue here is the lack of support from the OpenAPI specification / JSON schema to support object references.

In my "google endeavours" the waters are muddied a lot by content around references in OAS / JSON schema themselves ... go figure.

I've been looking into JSON Reference and Javascript Object Graph, but I have found no hooks to incorporate these ideas into an OAS schema.

Model reference as string

The most likely route to take for me is to model the start and destination properties of Edge as strings. That at least solves the issues above. This does bring up a new issue: clients generated by swagger are less intuitive to use:

new Edge()
   .start(vertexA.getId())
   .destination(vertexB.getId())

instead of

new Edge()
   .start(vertexA)
   .destination(vertexB)

The issue is worse even when reading responses:

Vertex start = graph.getVertices().stream()
     .filter(v -> v.getId().equals(edge.getStart()))
     .findFirst();
Vertex destination = graph.getVertices().stream()
     .filter(v -> v.getId().equals(edge.getDestination()))
     .findFirst();

instead of

Vertex start = edge.getStart();
Vertex destination = edge.getDestination();

To make matters even worse still is that the API will have a class hierarchy for both Vertex and Edge. When using string as type for the start and destination properties, the type safety in the client is down the drain.

Help

Does anyone have experience with this type of schema? Any advice on how to model the schema and/or support in client generators?

1

1 Answers

0
votes

I'm experiencing exactly the same, especially regarding the google search: there are lot of JSON schema reference hits, none of them relevant to complex object graph serialization.

What I did on the server side (java): I have my own object serializer, which smart enough, to handle object references. Every object has an id. When the object first serialized, the serializer's output is the object JSON representation. When an object reoccur in the graph, the serializer only outputs the object reference with #objectid.

For example:

    {
    "created": "05/03/2020 17:49:08",
    "name": "Object Group [5109]",
    "objectID": 5109,
    "elements": [
        {
            "created": "05/03/2020 17:49:08",
            "name": "Element [5110]",
            "description": "Object example [5109]",
            "objectID": 5110
            "parent": #5109
        },
       ...
    ]
}

Of course if you want to represent the object graph properly on the client side, this has to be deserialized in JavaScript code, and set the client side object references during deserialization. I don't know any mechanism for this in openapi generated clients.