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

Field references #1646

Closed
gareth-ib opened this issue Jul 31, 2018 · 23 comments
Closed

Field references #1646

gareth-ib opened this issue Jul 31, 2018 · 23 comments

Comments

@gareth-ib
Copy link

gareth-ib commented Jul 31, 2018

I can't find a firm declaration on this, but I can see it in SwaggerUI, so my question is, is this considered a valid supported way to define that a field in object1 relates to a field in object2.

To say that the photo::album_id field, relates to the album::id field.

So generated code can automatically organize multiple lists of objects.

"definitions": {
	"photo": {
		"type": "object",
		"properties": {
			"id":		{ "type": "integer" },
			"album_id":	{ "$ref": "#/definitions/album/properties/id" }
		},
	},
	"album": {
		"type": "object",
		"properties": {
			"id": { "type": "integer" }
		},
	},
},

If this is valid, or some other way is valid; can an a usage please be added to the examples?

And if not valid then can this or something similar be added?

thanks

@tedepstein
Copy link
Contributor

tedepstein commented Jul 31, 2018

@gareth-ib , the JSON reference you're using is valid, but the only formal semantics of the reference are those conferred by the referent schema itself. In other words, the only thing your schema says about the photo.id property is that it must carry an integer value, because that's what the referenced #/definitions/album/properties/id schema says.

It's possible, theoretically, for a code generator to give special treatment to property references like this, treating them as foreign key references, and generating some object-relational mapping configuration or logic according to this. But it could be fragile, because certain parsers or pre-processors might resolve the $ref before the code generator sees it; or might just not provide a programming API that distinguishes a reference from an inline schema.

Also, more generally, ascribing a special meaning to a standard construct whose semantics are already defined is asking for trouble, IMO. The special meaning you're ascribing might not be what's intended, and this limits interoperability.

If you need foreign key reference semantics, I'd suggest using specification extensions, and writing your code generator so it recognizes these extension properties.

@gareth-ib
Copy link
Author

yeah I need Foreign Key logic specifically, not just the schema mirroring.

I was hoping there was an existing functionality I wasn't seeing so that I can use the generators that exist. Making my own generator ( I need Android and iOS ) is a bit outta my scope.

Maybe a concept like...

"album_id":	{ "$fk": "#/definitions/album/properties/id" }

@silkentrance
Copy link

@gareth-ib you do not design your APIs this way, there is no notion of a foreign key reference. Just make it also an integer and keep in mind that it is actually a reference to an instance of type album.

@gareth-ib
Copy link
Author

gareth-ib commented Aug 3, 2018

@silkentrance But data always has the concept of related data. So an API with lots of different objects being passed through it will have a myriad of relational concepts. country, state, city, address, member, profile, anything... So ideally there would be a way to document and generate handlers for that instead of the client programmers needing to learn all the relations that exist in an entire API system.
Example a list of 50 profiles, all with a country_id, and separately a unique list of their countries as full objects, which ends up being 2 instances of the country object.
As opposed to a client project needing to pre-hard-code relations between objects

@silkentrance
Copy link

silkentrance commented Aug 3, 2018

Then I presume you would have to extend upon the existing templates for rendering out the code, additionally introducing vendor specific properties, e.g. x-orm-many-to-one: Foobar. And this is also very specific to the ORM that you are using.

I do not think that this can be handled by the OAI specification at all.

@gareth-ib
Copy link
Author

gareth-ib commented Aug 3, 2018

Perhaps for complex concepts like that. But at the moment I'm just looking for object1:field to object2:field

@silkentrance
Copy link

Again, the OAI has no notion about the persistence of your data nor the relation between your data. And in my opinion it should stay that way. This makes it simple.

@gareth-ib
Copy link
Author

I can't think of one scenario where code being able to automatically know data structure is a bad thing

@silkentrance
Copy link

@gareth-ib yes, it is surely not a bad thing to have, but again, this is something very specific to your persistence layer and not something that could be handled at the API level, except of course when using customised code generation templates and assorted x-... hints that will be evaluated by these templates in order to generate the required code.

But then again, and thinking of layered architectures, that code generator would have to also create the required annotations (thinking JPA/Hibernate here) on the generated classes. And it is still the question of whether you would want to have such annotations on your service's boundary and the objects that act as DTOs for transferring data to and receiving data from external clients of your API.

@gareth-ib
Copy link
Author

Well what I'm picturing is in the realm of definitions cross-referencing their FK's to each other... so a generator ideally would be able to handle that. Since the config would already be referencing the full object structure in the places they load

@gareth-ib
Copy link
Author

gareth-ib commented Aug 3, 2018

this is the structure I'm piggybacking off of : https://popshops.com/support/api-3-new-features

which has objects in lists contained by their object type

@silkentrance
Copy link

silkentrance commented Aug 3, 2018

The API "specification" you provided a link to introduces an optional type and a sort of mandatory kind property. Something that will be evaluated by the application's (business) logic.

So basically, on the actual specification side, this renders out to

ParameterType:
  type: object
  properties:
    type:
      type: string
    kind:
      type: string
      enum:
        - something
        - ortheother

There is no FK here, just an example on how to use the API.

And considering

Parameters: The parameters block is used to list all parameters that were used to build up the response information. This can be used for troubleshooting problems, as well as rebuilding links by knowing how you got to the information you are currently viewing.

this is just meant as additional information that is being passed to the client. With the client having to implement the knowledge on what each of the parameters in the return result means. Very similar to hyper-schemas but different. See for example #370

See also https://swagger.io/docs/specification/links/

@gareth-ib
Copy link
Author

I'm referring to the fact that the objects in there contain id's for the related objects.

@silkentrance
Copy link

Yes they do. And this is where hyper-schema comes into play. With that, you can define the relations between your objects.

@gareth-ib
Copy link
Author

link as in the "links" thing that does another url call? How would that relate to content that is included in the same API response?

@silkentrance
Copy link

silkentrance commented Aug 4, 2018

Basically, this is just an indirection. The client can use the information to traverse for example from a photo to its containing album. It may also use the information to present a hyper link on the same page as the photo in order for the user to navigate to the containing album and so on. All of this without even knowing that there is a FK relationship between album and its contained photos.
So everything is loosely coupled, which is a good thing.

@gareth-ib
Copy link
Author

yeah that's useful for not at all the scenario I'm addressing...

@silkentrance
Copy link

silkentrance commented Aug 4, 2018

It is a necessary abstraction as the code generator cannot know your server side nor your client side architecture, which may be multi layered or even multi tiered.

@gareth-ib
Copy link
Author

gareth-ib commented Aug 4, 2018

By "can not" you mean, doesn't currently. What I'm suggesting is to solve that by defining it.

Perhaps along the lines of...

"$fk" : [
   {
      "$parentFields" : [ "country_id" ],
      "#definitions/country" : [ "id" ],
   }
]

Multiple tiers handle themselves by being defined on each parent object. Exactly the same as a database

@silkentrance
Copy link

Well, I am actually getting tired of discussing this. Let's see what the POs think about this and whether it is feasible to have such a feature in addition to what is already there incl. also the ability to add x- vendor specific code generation hints to the spec and also the ability to implement custom code generators based on that.

@rsmckinney
Copy link

Was this topic ever resolved, one way or another? I can see both sides here. On one hand, OpenAPI is a higher level API that should not favor any specific persistence layer. On the other hand, probably a fair chunk if not a majority of OpenAPI consumers use relational databases for at least part of the backing storage. It feels like there should be another layer to accommodate and standardize how the RDB crowd uses OpenAPI, no?

@handrews
Copy link
Member

This discussion seems to have fizzled out a year ago. The underlying issue is really a question about JSON Schema, so I'm going to link to the relevant issue over there (json-schema-org/json-schema-spec#855) and close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants