Closed DrewML closed 4 years ago
We will have two naming approaches in the system for some time.
Since the proposed name uid
is not giving any substantial benefits, like being the default cache key for client side libraries, lets look at two pairs of names in the system:
uid
and id
id_v2
and id
It looks like the question boils down to which pair is less confusing.
In my personal opinion the second option is less confusing because it follows the same versioning principle we already accepted for all fields. It is also intuitive.
If I was a developer seeing uid
in some places, id
in other places for the first time, it would raise question "why".
@paliarush Thank you for the feedback!
It looks like the question boils down to which pair is less confusing.
IMHO, there is one additional consideration here: how this field looks in the schema in 5 years? I would hope that 5 years from now, we have one, well-known field to represent the ID of an object type (rather than id_v3
, id_v4
). Adding a version to the ID field feels like we're implicitly agreeing to a versioning scheme for this field, and I'm not convinced that's desirable.
uid
/guid
/identifier
/etc is not versioned, and ships with the message "this is now the ID field moving forward, so look for this field"id_v2
says "this is the ID field today, but it's likely to change in the future, so keep an eye out for id_v3
".Unlike other fields that are specific to their domain objects, IDs are a very general API feature. I'm of the opinion that this should be the last time we change this field name. Is there a scenario where we ever see ourselves having an id_v3
(Remember that ID
type protects us from breaking changes due to format changes)?
It is also intuitive.
I would (respectfully) argue that uid
is a pretty standard abbreviation for unique identifier , so I'd imagine a good chunk of developers would at least know uid
== "some form of ID." At that point, they'll have the same question as id_v2
: "why is there a new ID field now?" I think that problem is unavoidable.
From the history of Magento we can assume that deprecated fields may stay there for more than 5 years.
I am not saying that the name uid
is not intuitive by itself. I am just saying that when developer sees id
in some objects, uid
in other objects - it may raise more questions than seeing id
and id_v2
. This statement is subjective though.
Additionally, there is a chance of id_v3
in the future due to some semantical changes, which may affect clients using id
not only for caching purposes, but also in business logic. In this case I would also prefer id_v3
instead of coming up with yet another alternative naming for the same field.
One solution could be to rename all ids in the system to uid
and deprecate the rest. This will bring consistency and keep the name without the suffix. Can the client have a generic override for cache key saying that all objects will have uid
and not id
?
From the history of Magento we can assume that deprecated fields may stay there for more than 5 years.
Totally separate (likely hours long) discussion, but sounds like we need some more general guidelines for how we handle deprecations (remove after X versions, X years, X decades, etc). But I know better than to try and address that in this ticket!.
I am not saying that the name uid is not intuitive by itself. I am just saying that when developer sees id in some objects, uid in other objects - it may raise more questions than seeing id and id_v2. This statement is subjective though.
I think it's safe to say that we both agree that using almost any name besides id
, while also still having the old id
fields, is confusing, which is good that we agree and bad that it's confusing 😆
Additionally, there is a chance of id_v3 in the future due to some semantical changes, which may affect clients using id not only for caching purposes, but also in business logic. In this case I would also prefer id_v3 instead of coming up with yet another alternative naming for the same field.
This is the part that I'm skeptical about, and really the driving motivation behind this PR. Can you give some examples of semantic changes that would lead to us introduce another ID field on an object? I think this is an important discussion to have.
Can the client have a generic override for cache key saying that all objects will have uid and not id?
Yep! Typically just passing in a callback with the signature (object: ObjectType) => string | string[]
. That's why I think it's important for us to get 1 stable ID for caching and commit to it. We know a bit of pressure on the API can lead to service degradation, so having consistent caching for the client benefits both shoppers and DevOps.
Let's have a little broader discussion to rename all IDs to uid
then and make sure we introduce uid
to every entity (not every object though). Looks like we both are okay with this option.
Let's have a little broader discussion to rename all IDs to uid then and make sure we introduce uid to every entity (not every object though). Looks like we both are okay with this option.
Sounds good to me!
Adding @mhaack for visibility. @mhaack please provide feedback.
Additional reading that's helpful:
Our API currently doesn't support the ability to lookup an arbitrary entity by ID, which is desirable for some GraphQL clients. A consistent ID/type will open up the option to support this in the future.
@DrewML - I won't be able to make the discussion, but had an additional point I wanted to make sure was represented.
On the same theme as automatic caching using id
fields, another common setup for Apollo clients is to include their eslint plugin into your app to help catch common mistakes (eg. id
is required if available, no deprecated fields). As you might see with the two rule examples I provided, moving forward with an id
field that is not useful to the app and is flagged as deprecated means anyone using our API is going to have to:
uuid
).id
is not the actual ID, in each query or mutation response of that type they'll need to eslint-disable // eslint-enable
that whole operation to suppress one of those two eslint rules.I don't know if there was still an argument for just allowing backwards incompatible changes to id
fields, but wanted to provide some additional issues developers are going to run into if we proceed with the new field approach.
As a moonshot alternative, if we're going to introduce a new ID field, I propose we do it across all types and deprecate id
everywhere. At least that way you could write cache maps and eslint rules to always expect uuid
, instead of having to manually determine for each operation which id
field is actually correct.
I don't know if there was still an argument for just allowing backwards incompatible changes to id fields
I think everything is on the table. IMHO this is the best idea if the only motivation is consistency. But, I suspect we might not be able to reach consensus on a breaking change of that size.
As a moonshot alternative, if we're going to introduce a new ID field, I propose we do it across all types and deprecate id everywhere. At least that way you could write cache maps and eslint rules to always expect uuid, instead of having to manually determine for each operation which id field is actually correct.
That's definitely what I'm advocating for 👍 1 well-known ID field, for every entity.
Meeting scheduled today for us all to discuss. Here's a quick summary we can review when we kick off the meeting:
Summary of problem so far: This change is motivated by 2 tangentially related issues:
Here is what has been discussed in this PR so far:
id
with an Int
type. These types are not opaque, and have locked us into being unable to switch to something like UUIDsuid
) that can always reliably be used as a cache key (mentioned by @tjwiebell in some other issues/Slack discussions)
Query.node(id: ID)
for granular cache updatesid
without a one-time breaking change
We had a productive meeting, with some outcomes!
Attendees:
Outcomes:
id_v{num}
)uid
as the unique identifier for object types that represent entitiesuid
field, and no id
fieldid
fields should be deprecated, and those types should have a uid
field added with type ID
id
values before we can deprecate the id
fields themselves (some risk here)Action Items:
uid
field with an ID
typeid
deprecations and uid
additionsuid
and ID
Regarding these items:
We'll need to update mutations that accept these id values before we can deprecate the id fields themselves (some risk here)
I will look into the risks and path forward for updating existing mutations to work with the output of the uid field with an ID type
Update: Definitely a breaking change, per feedback given in https://github.com/graphql/graphql-js/pull/2711.
query GetSomeEntity($var: String!) {
field1(id: $var) # If "id" is an ID type, this operation would break because of the variable
}
Will think about alternative paths - most obvious one is deprecating the existing queries/mutations that take a String
or Int
and replace them with a similar query/mutation that takes a proper ID. Will collect a list and look at what the impact would be.
Original Comment Details (Incorrect)
This (if approved) impacts an in-flight PR: https://github.com/magento/magento2/pull/28210
These changes are based on discussions I've had with @prabhuram93 and @nrkapoor.
There were a few concerns I wanted to address:
We should be using the
ID
type for IDs, because we don't want clients using them for anything but lookups. Mentioned in a separate design documentThe document mentioned that
id_v2
was a temporary field until we start using UUIDs. If we use theID
type, though, we shouldn't need a temporary field. If a client deploys a new version of the GraphQL API (after we switch from base64 >> uuid) and a client has cache entries for the old IDs, those old entries just won't be looked up in the client-side cache anymore. No loss/corruption should happenI believe this matches the vision for every entity to have a globally unique ID, but with less downstream changes for clients. Please correct me if I'm wrong!
@nrkapoor and I discussed various names for the field. I've gone with
uid
in the PR, but happy to change if we can reach consensus on a different name. Here's the names we discussed:uuid
: Bad because UUID is a specific encoding algorithm, and a client should not care about thatgid
: "Global Identifier"uid
: "Unique Identifier"_id
: Just kind of uglyidentifier
: Verbose, but accurateNote: It's worth knowing that popular GraphQL client libraries (Apollo/urql) have default cache configurations that look for the field name
id
or_id
on Object Types. Whatever new field we choose, we should be consistent going forward, as each headless solution will now need to customize their client to use this new cache key. See https://www.apollographql.com/docs/react/caching/cache-configuration/#custom-identifiers