Created by: Jonas1893
This PR adds support for openapi specs date
format and fixes the points addressed in https://github.com/OpenAPITools/openapi-generator/issues/5280
Summary
In order to properly support OpenAPIs date
type, I propose to introduce a new type because Swifts Date
type alone is not sufficient - and neither is any other type from the Swift standard lib like DateComponent
s for reasons explained later. Sorry for the wall of text but dates, calendars and timezones are hard to reason about
Because there is now a new type used in API Models this is a breaking change. We discussed in the linked initial PR that we want to implement this new functionality behind a flag to stay backwards compatible and to be able to ship it with a minor release.
Motivation
swift5 generator does map both OpenAPIs date
and date-time
formats to Swifts Date
type. This is fine for date-time
which is a specific point in time but can be problematic for date
which is not a specific point in time but rather a time frame. OpenAPI spec defines data type date
'As defined by full-date - RFC3339' and RFC3339 defines a full-date basically as a day in the gregorian calendar.
Let's use an example. In an API where a request model defines a birthday
property like this:
properties:
birthday:
type: date
example: "2019-05-17"
swift5 generator would generate an API model with a property birthday
with datatype Date
. There are two problems here:
- Swift
Date
s always contain time information. The information for the generator whether the date should be encoded todate-time
or justdate
format is therefor lost completely when usingDate
in the API models. That's why currently generator will always serializeDate
s intodate-time
format. - Even if we would know that we need to serialize into
date
and notdate-time
: Since SwiftsDate
is "A specific point in time, independent of any calendar or time zone.", any date (as a timeframe) supplied to the requst model MUST have been created using a gregorian calendar and timezone GMT+0. As soon as this is not the case and e.g. a date has been picked using a DatePicker in an iOS app using gregorian calendar but with a timezone offset of GMT+5 it is possible that the serializedDate
is now in a different day on the gregorian calendar in GMT+0. So using this example, a wrongdate
would be sent to the server if thisDate
would be supplied without normalization to GMT+0.
The problem is more severe when encoding (sending something to a REST API) than in the decoding case, because when decoding we can safely assume ISO8601 standards are satisfied by the server and just try to decode multiple times using a different format. Still, a Date
is being returned by the generator obfuscating the fact that this Date
object including time information needs to be interpreted as "a full day in the gregorian calendar in timezone GMT+0". Knowledge of the API spec in addition to the generated code is currently required to properly interpret the Date
in business logic of the consumer of the generated API.
Technical changes in this PR
- New type
DateWithoutTime
is introduced for openapi specsdate
format which addresses the problems explained above. With the timezone information we can properly normalize to GMT+0. The new type enables generator logic to easily decide whether we need to encode todate
ordate-time
. - New
withoutTime
formatter is added to customOpenISO8601
formatter class using the same fallback mechanism as before when decoding dates. This change could also be contributed in a separate PR because it is backwards compatible and adds support for decoding(not encoding!)date
to the generator.
Reasoning for the new type
The information whether a swagger attribute encodes to date
or date-time
somehow needs to be passed on from API models to generator logic. I tried fiddling with the models mustache templates (and we did this to workaround the current generator limitation in our project) but still we need to add this information for each attribute of type Date
- so either we create tuples (which also breaks the existing APIs) or we create a new type.
Why not use DateComponents?
A lengthy discussion about why DateComponents are not suited for (de-)/encoding dates can be read here https://forums.swift.org/t/pitch-datecomponents-encoding-decoding-strategy-in-json-encoder-decoder/6602
In short and specific to our use case: DateComponents
can be used to create Dates that do not exist or where days or month information can be omitted. They are therefor not suited to be used directly in our API models.
PR checklist
-
Read the contribution guidelines. -
Pull Request title clearly describes the work in the pull request and Pull Request description provides details about how to validate the work. Missing information here may result in delayed response from the community. -
Run the following to build the project and update samples: ./mvnw clean package ./bin/generate-samples.sh ./bin/utils/export_docs_generators.sh
./bin/generate-samples.sh bin/configs/java*
. For Windows users, please run the script in Git BASH. -
File the PR against the correct branch: master
(6.1.0) (minor release - breaking changes with fallbacks),7.0.x
(breaking changes without fallbacks) -
If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request. -> @4brunu as discussed: this is the PR with flag against master branch
Declaration
The program was tested solely for our own use cases, which might differ from yours.