Problem/Motivation
- #2824717: Add a format constraint to DateTimeItem to provide REST error message added a validation constraint. This already improves the REST DX (== RX). Because now REST clients are at least told what they're doing wrong.
- But we should go further: we should allow
POSTing andPATCHing with datetime fields having values in any timezone.
Proposed resolution
Do something similar to #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX:
- implement a
DateTimeNormalizerclass - with normalization to/denormalization from RFC3339 timestamps
This would improve/unify the (de)normalization of both DateTimeItem and DateRangeItem fields.
Remaining tasks
TBD
User interface changes
None.
API changes
None.
Data model changes
None.
Comments
Comment #2
wim leersPer #2824717-62: Add a format constraint to DateTimeItem to provide REST error message and -63, this is blocked on that issue.
Comment #3
mpdonadioThought about this one the commute home tonight.
We have #2716891: DateTimeIso8601::setDateTime() vs. DateTimeItem::schema(): (at least) one of them is broken, which aims to solve a similar problem, but not for REST. That issue would change the storage format to include +00:00 (explicit UTC) and potentially handle conversion to UTC in the setter. I don't see these as mutually exclusive problems anymore. In fact, I think having a denormalizer for these fields that behave in the exact same manner as timestamps (permissive to common input formats) is good (1) for consistency and (2) isolates interface from implementation. The denormalizer will help future proof any changes to field storage internals.
I also think it would be beneficial to add a normalize (with BC) the responses to the same \DateTime::RFC3339 format, again for consistency. Again, the outside world doesn't need to care about how we store stuff and all timestamps/dates in responses would be the same and we can mess with internals w/o breaking APIs.
Comment #4
wim leers+1!
+1! I'd like to add: it's okay to expose "default Entity/Field API internal behavior by default", but it's not ideal. Not every REST client has the ability to step through PHP code with Xdebug. So we should A) give error feedback appropriate for REST clients, B) try to meet expectations of "HTTP developers", not "PHP developers".
So, I wholeheartedly agree with #3, and especially with its conclusion, which explains it very well:
Comment #5
mpdonadio#2824717: Add a format constraint to DateTimeItem to provide REST error message is in (which formally blocked this), and #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX is in (which didn't block, but will provide guidance), so I think we can work on this again.
Since we don't have the constraint(s) on DateRangeItem, we should keep the scope of this to DateTimeItem.
For date+time items, the patch should be able to mirror the timestamp one (accept a few formats inbound, outbound ISO w/ TZ).
For date-only, I am not sure if we really need any change?
Comment #7
mpdonadioSo, I started to work on this, based off of the work in #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX.
In that patch, we have a Normalizer in serialization and hal. So, to prevent cross-contamination and to allow people to not have to have HAL enabled, we need two Normalizer services in Drupal\datetime\Normalizer, with the appropriate priorities?
Comment #8
wim leersCorrect, that'd be in line with what #2768651: Let TimestampItem (de)normalize to/from RFC3339 timestamps, not UNIX timestamps, for better DX did.
However… we realized in #2901429: JSON API Extras @ResourceFieldEnhancer plugins should also be applied to filter values and #2860350: Document why JSON API only supports @DataType-level normalizers that adding
@FieldType-plugin-level normalizers is a bad idea, because they need to be written for not onlyserialization.module(default normalization) andhal.module(HAL normalization), but alsojsonapi.module(JSON:API normalization) and any other alternative normalization. So that is unfortunate.The solution lies in not adding more
@FieldType-plugin-level normalizers, but instead working at the@DataType-plugin level. Because then it's automatically picked up by all normalizations.Comment #9
wim leersSo based on #8, we'd want this issue to add a
\Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601normalizer. Then it'll work everywhere automatically, in all 3 normalizations mentioned in #8 :)Comment #10
wim leersWe should also look at the normalization of fields configured to be "date-only". That would solve #2870609: [PP-1] Core Date field is serialized as String instead of timestamp/long.
Comment #11
wim leersWithout this, and especially without test coverage, how to deal with
DateTimeItemfields via core's REST API and contrib's JSON API is ill-defined, and may change without us knowing (== BC break).Bumping to major for that reason.
Comment #12
wim leersIf this would do what #8 + #9 say, then #2918554: [PP-1] Let DateRangeItem (de)normalize to/from RFC3339 becomes a duplicate.
Because:
\Drupal\datetime\Plugin\Field\FieldType\DateTimeItemThe only non-internal field here is
value, which uses thedatetime_iso8601@DataTypeplugin.\Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItemThe only non-internal fields here are
valueandend_value, both of which also use thedatetime_iso8601@DataTypeplugin.Comment #13
wim leersIOW: adding a
\Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601(de)normalizer would fix the DX of both field types!Comment #14
wim leersAdded to #2905563: REST: top priorities for Drupal 8.5.x.
Comment #15
wim leersOver at #2926508-18: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API, I'm proposing to deal with several issues at the same time, because it turns out there's a single elegant solution that will fix it all! For now, just postponing this, and not marking it as a duplicate.
Comment #16
mpdonadioJust read other patch, and agree with #15.
Comment #17
wim leersGreat :)
Let's keep this open for now, until #2926508: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API matures a bit more. Perhaps we'll want to reduce scope there, and move part of that patch to this issue.
Comment #18
wim leersI'm pretty sure #2926508-24: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API means we can close this!
Comment #19
wim leersSee #2913941 and specifically #2913941-6: [PP-1] Fields using the DateTimeIso8601 @DataType are missing an explicit time zone: missing a normalizer, which is the JSON API equivalent to this issue. If we'd solve this, then we'd also solve it for JSON API. Doing that over at #2926508-33: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API.
Comment #22
wim leers#2926508: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API fixed this, and added explicit tests! 🎉