Created by: thomasphansen
This fixes #12926 (closed) and addresses #728 for the specific PHP client.
When handling Accept headers, the current behavior of the php OpenAPIGenerator is:
- If there is none in the api description, don't send one.
- If one of them matches a "json-like" RE, send only "application/json" and ignore the others
- otherwise, concatenate all them and send it.
The first and third behaviors are fine, but the second one has some issues:
- if the API description includes parameters for the "json-like" Accept header, they will be simply disregarded. This can be a problem if those parameters are mandatory for that API.
- scenarios like the one described in #12926 (closed) cannot be solved without using a middleware in the http client, to change the Accept header just before sending the request. This is not a good experience for the user, IMO, since the proper Accept headers are already described in the OpenAPI description - we should just use them properly.
In order to solve this, both mentioned issues suggest using Quality Values (which I'll abbreviate as QV) to define the priority of the Accept headers. QV's are described in IETF RFC 9110, item 12.4.2, and their usage is described in the same RFC, item 12.5.1. Link to the RFC: https://www.rfc-editor.org/rfc/rfc9110.html#section-12.4.2
This PR implements a solution for a more convenient way of handling the Accept headers, using the following rules:
- if there is no Accept header, send none (same as before)
- if there is only one Accept header, send it unchanged
- if there are multiple Accept headers, but none are "json-like", send them all (same as before)
- otherwise, use QV's (weights) to give the highest priority to "application/json"-like headers, followed by other "json-like" headers, followed by all other headers.
This last rule can be a bit tricky, especially if the given Accept headers already have QV's. To handle this properly, this PR recalculates all quality codes, by splitting the headers in three categories ('application/json'-like, 'json'-like, 'non-json'-like), ordering each one by QV's and then attributing new QV's for all them, respecting the categories order (json-related first) and the internal order for each category.
But calculating the new values for the QV's is also a bit tricky: they vary from 0.001 to 1 (not having a QV implicitly means a value of 1), and most of the time get values like "q=0.9", "q=0.8" and so on. To create a sequence that emulates a "human" usage (and avoid values like "q=0.999", "q=0.998" etc), I used a logarithmic expression that generates a series like 1000, 900, 800, ... 100, 90, 80, ... 10, 9, 8 ... 2, 1, resulting in QV's like "q=1", "q=0.9", "q=0.8", ... "q=0.1", "q=0.09", "q=0.08" etc.
Since the series is limited, it will work perfectly for up to 28 headers with QV's - for more than that (which is extremely unlikely to happen, I'd say), the QV's will fallback to the poor "q=0.999"-like behavior - which is still valid according to the RFC.
More details can be found in the comments, directly in the code. New tests are also present, both for the headers selection and for the QV's generation.
Hope you guys like it!
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] @jebentier, @dkarlovi, @mandrean, @jfastnacht, @ybelenko, @renepardon