Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relationship properties #601

Closed
ralfhandl opened this issue Mar 18, 2016 · 10 comments
Closed

Relationship properties #601

ralfhandl opened this issue Mar 18, 2016 · 10 comments
Labels
links Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk

Comments

@ralfhandl
Copy link
Contributor

Relationships are an important part of an API or a data model: People have Friends, People have Hobbies, which are shared by other People, ...

OData represents relationships as a special kind of property, a so-called navigation property which allows retrieving related entities, and also retrieving an entity together with related entities:

As the last example shows it makes sense to model navigation properties just as "data" properties in the /definitions section as they may be part of the response if requested with $expand. It is also necessary to tag them as special properties, and include additional metadata about the relationship:

            "Products": {
                "type": "array",
                "items": {
                    "$ref": "#/definitions/ODataDemo.Product"
                },
                "x-relationship": {
                    "partner": "Category",
                    "onDelete": {
                        "action": "Cascade"
                    }                    }
            }
        }
    },

Partner is the navigation property in the target type that leads back to the current type, onDelete describes potential side-effects of deleting an entity of the current type, and referentialConstraints describe value dependencies to the related entity.

Anyone else having similar concepts/constructs in their APIs that would make it worth making this a first-class concept in OpenAPI?

@sensibleish
Copy link

I recently starting using OAS to create a big set of models for the first time. It is very frustrating not to have a standard way to express relationships between model instances. I'm creating schema as planning for a content management system. I likely won't be actually importing my OAS docs, but it seemed like the best way to document in advance of choosing a specific CMS. I think I have two basic needs that seem like a sub-set of what you described:

  1. Create attributes that are a reference (or an array of references) to entities of one or more specified types.
  2. Indicate that a referenced entity should be included in the referring entity in an API response. When a client requests a restaurant, includes the restaurant's menus which are stored using distinct models because they are complex.

I suspect I could clunkily handle case 1 using a custom URI scheme. I could create a string attribute strings with format set to uri and enum choices like companyname:content-types:restaurant. It expresses what I need to a human, but that's it.

@handrews
Copy link
Member

@sensibleish could you write out a bit of an example of what you're trying to do? At casual glance I'm having trouble distinguishing what you're talking about from $ref-ing schemas.

@sensibleish
Copy link

sensibleish commented Jan 19, 2020

As far as I can tell, $ref is a convenience for combining chunks of schema code. It's not for creating relationships between separate, complete models. Say you have a model representing an entertainment venue and a model representing a performer. The venue model has an attribute listing performers (and/or the performer model has an attribute listing venues where the performer appears). You could also use the original post example of a person model with an attribute listing the person's friends, who are likely represented using the same model. These are all distinct entities. When retrieving any one entity, you do not necessarily want to follow the references and include other entities‘ content. But if you used $ref, to my understanding you'd indicate that performers are actually part of the venue model. If you have references in both directions, you create an infinite loop.

I don't have an academic understanding of these issues. I suspect what I'm after is essentially graph functionality. I have a set of models with clear boundaries and I want to indicate relationships between instances of the models.

@handrews
Copy link
Member

@sensibleish I think there are a couple of things going on here which are probably contributing to the confusion. When you say things like:

You could also use your original post example of a person model with an attribute listing the person's friends, who are likely represented using the same model. These are all distinct entities. When retrieving any one entity, you do not necessarily want to follow the references and include other entities‘ content.

Are you talking about having an option in the retrieval process (e.g. a URL parameter or whatever) that would either cause a list of links to friends to show up, or actually cause all of the friends to be embedded in that list in place of the links?

There are several issues there:

  • How to model the case of just having links
  • How to model the case of embedding the friend objects (who are also of type person)
  • How to handle selecting links vs embedding
  • Whether and how to handle relationship depth (e.g. do you want friends-of-friends embedded further, or do you just want one level of friends)

I can't answer your questions further without understanding which of these you understand, and which of these you see as a problem. Also, I need to know if you are concerned about validation, code generation, documentation generation, ui generation, etc., as there are different tooling challenges around these different use cases. In the case of code generation, it also matters whether you are considering strongly statically typed languages or not.

@sensibleish
Copy link

Appreciate the discussion. As you point out, modeling and transmission/retrieval lead to different concerns. I am working to create a set of models that mostly represent real-world things, as a reference for a bunch of future work. If I were planning for a relational database, I think these "reference" needs would be easily handled by foreign keys. But these models will mostly be used in an ecosystem of systems talking RESTful APIs, so transmission/retrieval concerns can't be ignored.

We haven't chosen the new content management system, which might have dictated some of my decisions here. There will likely not be a 1:1 mapping between OpenAPI model attribute data types and the CMS features. For example, the current CMS has an attribute type that is explicitly a reference to another object inside the CMS. The CMS will (hopefully) have some way of expressing whether to embed linked objects in a response, depth of references to follow, etc.

Happy to have any suggestions you may offer. Mostly just want to express support for OpenAPI having ways to express some of these things.

@handrews
Copy link
Member

@sensibleish I'm one of the main JSON Schema spec authors, and one reason I'm working with the OpenAPI TSC is to work through issues where new sets of JSON Schema keywords (separate from validation) would help solve data modeling problems.

At a high level, I think some of that might help you. But your descriptions are too general for me to propose any particular solutions. I think I would need to see some possible schema (and OAS operation) arrangements you've considered in order to go into any more detail.

Whether you can share those or not, this sort of work will continue, either in this repository or elsewhere. The version of JSON Schema that is being adopted in OAS 3.1 makes it much easier for 3rd parties to design extension keywords, although of course tooling support is not automatic!

@sensibleish
Copy link

I appreciate your attention! I will be more specific. The nightclub-performer example was a real one. I am creating a set of models for business entities that will be a reference for configuring a new content management system. If the CMS can directly ingest the spec to configure itself, great. It would be even better if it could generate its own similarly expressive spec to reflect its final configuration. OpenAPI seemed like the best way to make this documentation, with good viewing tools and easy collaboration. Maybe I'm misusing it.

We do not yet have use cases where code would arbitrarily crawl entity relationships, though I'll mention GraphQL below. Something like a web page template would use predetermined attributes. For the page template to display a nightclub's performers, it would already know which nightclub attribute contains that content.

I would like the models to let us express three things:

  1. That entity A has a relationship to entity B
  2. The nature of the relationship (for human understanding)
  3. What type(s) of entity B may be

For the nightclub model, I imagine I would:

  1. Indicate a relationship to performers by adding an attribute to hold references
  2. Indicate the nature of the relationship via the attribute's name (e.g. performers)
  3. Indicate the attribute's value will refer to performers by setting a property to an identifier for the performer model

Identifiers for models potentially seem very implementation-specific. For this immediate use, limiting to models in the same spec and using title as identifier might be enough. When I think about how these models and CMS fit into a larger ecosystem using GraphQL, some kind of namespaced identifier seems more useful. A key use for us with GraphQL is to get a list of products from an e-commerce service and add content for those products from the CMS. It will merge representations of the same entity from different systems, each with different attributes.

On embedding versus linking: almost all my use cases within the CMS are for linking. It is better to let content consumers choose when to include linked entity attributes (like via GraphQL). I have only a couple places where I would include an attribute by default but the attribute is complex enough and reusable enough to be a separate entity. There are workarounds much easier than adding embedding to a spec.

@good-faith
Copy link

@handrews @sensibleish - Looking for a way to spec relational data in OpenAPI I found this thread. GraphQl 's SDL (Scheme Definition Language) does scaffold relational data types.

Here a User has one blog. It is a 1 to 1 relation. A blog has many Comments. It is a 1 to Many relation. Each blog and each comment has one author. They are a 1 to 1 relation.

type User {
  id: ID! @unique
  comments: [Comment!]! @relation(name: "CommentAuthor", onDelete: CASCADE)
  blog: Blog @relation(name: "BlogOwner", onDelete: CASCADE)
}

type Blog {
  id: ID! @unique
  comments: [Comment!]! @relation(name: "Comments", onDelete: CASCADE)
  owner: User! @relation(name: "BlogOwner", onDelete: SET_NULL)
}

type Comment {
  id: ID! @unique
  blog: Blog! @relation(name: "Comments", onDelete: SET_NULL)
  author: User @relation(name: "CommentAuthor", onDelete: SET_NULL)
}

It also performs cascade deletes. Isn't there a tool that does introspection for OpenAPI that map foreign keys into an OpenAPI spec or do those relations not exists? Kinda of new to OpenAPI, but it does seem a $ref would be an interchangeable solution for type and similarly defined decorators could perform the same database operations.

@ralfhandl
Copy link
Contributor Author

See OAI/sig-moonwalk#58

@handrews handrews added the links label Jan 29, 2024
@handrews
Copy link
Member

This scale of change is best discussed in Moonwalk (and can be backported if relevant and we decide to keep the 3.x line going). Closing in favor of:

@handrews handrews added the Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk label May 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
links Moved to Moonwalk Issues that can be closed or migrated as being addressed in Moonwalk
Projects
None yet
Development

No branches or pull requests

3 participants