-
-
Notifications
You must be signed in to change notification settings - Fork 932
Refactor the responder to ease usage of content negotiation #590
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
Conversation
417b4a1
to
d413c8e
Compare
$resourceClass = $request->attributes->get('_resource_class'); | ||
$collectionOperationName = $request->attributes->get('_collection_operation_name'); | ||
$itemOperationName = $request->attributes->get('_item_operation_name'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the norm/denorm groups ?
We are using a custom ResponderViewListener
with a part on the norm groups (like I updated the docs):
I may be wrong but what about something like this (denorm will be maybe needed too) ?
$itemContext = $resourceMetadata->getItemOperationAttribute($itemOperationName, 'normalization_context', ['groups' => []], false);
$collectionContext = $resourceMetadata->getCollectionOperationAttribute($collectionOperationName, 'normalization_context', ['groups' => []], false);
if (!$itemContext['groups'] && !$collectionContext['groups']) {
$context = $resourceMetadata->getAttribute('normalization_context', []);
} else {
$context = array_merge($itemContext, $collectionContext);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm 👎 for this change. The whole context is set on the resource or on a specific operation. The more specific one is used. Changing dynamically the content of the context will lead to weird edge cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do I have to do then to have my collections groups taken in account with this change ?
Unregistring my Responder
and using this I don't get my collections & item groups taken in account on my route.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you post your @ApiResource
config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you set a context for a specific operation, you must set all groups in it. Groups from the resource will not be inherited (and this is intended). Are we talking about the same thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/**
* @ApiResource(iri="http://schema.org/Person", attributes={
* "filters"={"person.search", "person.order", "person.subscribers", "person.customSearch", "person.subscription"},
* "normalization_context"={"groups"={"person_default_output", "postal_address_output", "organ_affiliation_default_output", "organ_default_output", "name_default_output", "time_default_output", "person_responsability_default_output", "person_receipt_output", "person_status_default_output", "person_mandate_default_output", "mandate_default_output", "territory_default_output", "bank_default_output"}},
* "denormalization_context"={"groups"={"person_default_input", "postal_address_input", "organ_affiliation_default_input", "organ_default_input", "name_default_input", "time_default_input", "person_responsability_default_input", "person_status_default_input", "person_mandate_default_input", "mandate_default_input", "territory_default_input", "bank_default_input"}}
* }, itemOperations={
* "get"={"method"="GET"},
* "put"={"method"="PUT"},
* "export_subscribers"={
* "path"="people_export_subscribers",
* "method"="GET",
* },
* "export_emails"={
* "path"="people_export_emails",
* "method"="GET",
* }
* },
* collectionOperations={
* "get"={"method"="GET"},
* "post"={"method"="POST"},
* "export_members_email"={
* "path"="/people/export_members_email",
* "method"="GET",
* "pagination_enabled"=false,
* "normalization_context"={"groups"={"export_mails_output"}},
* }
* }
* )
*/
In this case, in my export_members_email
i've selected 3 fields. Using this route, with the CsvEncoder in the symfony's PR you made (thanks for that btw). I expect to get this three fields, instead of that I get everything
But in this case, they are inherited or I guess the normalization_context
in the collectionOperations
is not taken in account
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I just got why. I'll update the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you try the last commit fix the issue @Simperfit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does work properly for me thank you !
06db102
to
8084ee8
Compare
supported_formats -> formats is a BC Break, not a big one, but still. |
@Simperfit yes, it is the last chance to introduce BC break. When 2.0 will be tagged it will be too late :-) |
@@ -1,14 +1,14 @@ | |||
Feature: Create-Retrieve-Update-Delete with custom attribute | |||
Feature: Create-Retrieve-Update-Delete with a Overrode Operation context |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe Override
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an overridden operation
200eaeb
to
e645c28
Compare
e645c28
to
ead8c9d
Compare
ping @api-platform/core-team I want to merge it for the release of the first beta (probably tomorrow). |
* @throws RuntimeException | ||
* | ||
* @return array | ||
* @return array [$resourceClass, $collectionOperation, $itemOperation, $format] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should add an example with the @example
tag to be more clear on what those values can be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC @example
is used to import external files as examples: https://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.example.pkg.html
According to http://stackoverflow.com/questions/15414103/best-way-to-document-array-options-in-phpdoc there is not better way that what I've done here but I'm to change that if someone has something better :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A plain old example in the phpdoc to give an idea of what value you may have is good enough (besides what you added) IMO, @example
or not
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never been a fan of list
. It's not explicit at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hence the VO I wanted to introduce at some point :/ But what's important is that the user doesn't have to do a step by step debugging or a dump to understand what values are returned... the doc should be informative enough to avoid that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change that to an associative array with explicit keys for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just pushed a new commit with this change an a refactoring of request attributes usage.
* @author Kévin Dunglas <dunglas@gmail.com> | ||
*/ | ||
final class JsonLdEncoder extends JsonEncoder | ||
final class JsonLdEncoder implements EncoderInterface, DecoderInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we use JsonEncoder
directly for JSON-LD? There is no special handling whatsoever required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we need to override supports*
method and we tweak the options passed to JSON_ENCODE
for RFC compliance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we need to override supports* method
I don't quite understand that. Why can't we just set $format
to json
? Is there any benefit of using a different jsonld
format?
we tweak the options passed to JSON_ENCODE for RFC compliance
I thought that's what $context['json_encode_options']
is for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to use jsonld
as format to trigger JSON-LD normalizers when we call $serializer->serialize()
. An encore must support the jsonld
format.
ead8c9d
to
f095a3b
Compare
@api-platform/core-team OK to merge it right now? I'll open another PR following this one trying to move the item data provider call, the deserializer listener and the validator listener to the |
f095a3b
to
00e7221
Compare
00e7221
to
373af5b
Compare
This is working for us and its LGTM. So 👍 |
…ener Refactor the responder to ease usage of content negotiation
Thanks to this PR using the content negotiation feature of API Platform is much easier than before:
With this PR, enabling XML support for an existing API Platform app is just a matter of adding the following config:
The key is the format passed to the
$format
parameter of the Symfony Serializer. The value is an array of mime types corresponding to this format. Request containing anAccept
header matching one of the configured mime type will trigger content negotiation. The API will reply with the mime type requested (if supported). If the requested type is not supported (or if theAccept
header isn't set), the API will reply in the format configured to be the first.ping @Simperfit @clementtalleu @gorghoa.
TODO:
Switch backJsonLd
andHydra
actions to the ADR pattern