Skip to content

Add support for PATCH, refactor formats detection #2895

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

Merged
merged 22 commits into from
Jul 10, 2019

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Jul 1, 2019

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets #759 (partially)
License MIT
Doc PR api-platform/docs#878

Add proper support for partial modifications using the PATCH HTTP method. The first supported format will be JSON Merge Patch (RFC 7386), while JSON:API Patch will keep working. Supporting JSON Patch (RFC 6902) isn't a a goal as this format is not very popular in the wild, but could be done by leveraging the new infrastructure I'm building.

This PR also deprecates FormatsProviderInterface and OperationMethodResolverInterface and all there implementation in favor of populating the appropriate metadata. This approach as several benefits:

  • simplification of the code base
  • better performance because we move some run time logic to compile time
  • better flexibility

TODO:

  • Fix remaining deprecations
  • Set Serializer's skip_null_values to true when appropriate (always when PATCH is enabled?)
  • Use patch formats in docs
  • Find a way to block partial PUT (I've no clue of how to that for now, but actually it could be some documentation telling that there is no guarantees than doing that will work).

@dunglas dunglas added this to the 2.5.0 milestone Jul 1, 2019
@dkarlovi
Copy link
Contributor

dkarlovi commented Jul 2, 2019

Supporting JSON Patch (RFC 6902) isn't a a goal as this format is not very popular in the wild

As noted before,

It solves the partial collection management problem well and IMO it should be kept as a future option.

So having it not be "popular" doesn't mean it might not become so if well supported here.

Not saying you should implement it in this PR, of course.

@dunglas
Copy link
Member Author

dunglas commented Jul 2, 2019

So having it not be "popular" doesn't mean it might not become so if well supported here.

I'll be glad to merge support for it if someone contribute it (it's why the new system is designed to support several patch formats)! To clarify: it's not on my todo list (yet)!

@dunglas dunglas force-pushed the json-merge-patch branch 2 times, most recently from 5e84a32 to f63b3b3 Compare July 5, 2019 14:47
@dunglas dunglas force-pushed the json-merge-patch branch from 03bd7d9 to 5a61462 Compare July 8, 2019 07:50
@bendavies
Copy link
Contributor

bendavies commented Jul 8, 2019

Find a way to block partial PUT

how would you prevent a BC break here?
partial PUT is how we currently do PATCH of course. PUT with denormalization groups.

@jewome62
Copy link
Contributor

jewome62 commented Jul 8, 2019

Do you think implement the Header Accept-Patch ?
https://tools.ietf.org/html/rfc5789#section-3.1

That's just the new patchFormat but this is only on OPTIONS request.
So that's managed by nelmio/cors-bundle ?

@dunglas
Copy link
Member Author

dunglas commented Jul 8, 2019

yes it should be implemented in API Platform, but in a follow up PR (and maybe not in 2.5).

@dunglas dunglas marked this pull request as ready for review July 9, 2019 13:30
@dunglas dunglas force-pushed the json-merge-patch branch from 9f8ec42 to c760ad1 Compare July 9, 2019 13:31
@dunglas
Copy link
Member Author

dunglas commented Jul 9, 2019

how would you prevent a BC break here? partial PUT is how we currently do PATCH of course. PUT with denormalization groups.

It would be opt-in in 2.x, and opt-out in 3.x. But currently I struggle to find a god way to implement this: https://twitter.com/dunglas/status/1148578034787782656

@dunglas dunglas merged commit a62a077 into api-platform:master Jul 10, 2019
@dunglas dunglas deleted the json-merge-patch branch July 10, 2019 16:41
$errorFormats = $this->getFormats($config['error_formats']);

$this->registerCommonConfiguration($container, $config, $loader, $formats, $errorFormats);
// Backward Compatibility layer
if (isset($formats['jsonapi']) && !isset($patchFormats['jsonapi'])) {
Copy link
Contributor

@teohhanhui teohhanhui Jul 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really think we should deprecate specifying the format keys, and just use the mime type directly.

EDIT: Hmm... I see it's more complicated than that.

@@ -163,6 +163,7 @@ public function getConfigTreeBuilder()
'json' => ['mime_types' => ['application/json']], // Swagger support
'html' => ['mime_types' => ['text/html']], // Swagger UI support
]);
$this->addFormatSection($rootNode, 'patch_formats', []);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem like a good default?

*/
public function __construct(Negotiator $negotiator, /* FormatsProviderInterface */ $formatsProvider)
public function __construct(Negotiator $negotiator, $resourceMetadataFactory, array $formats = [])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to do something like this in so many places. Otherwise we'll end up with lots of holes in our arguments in 3.0 😆

@@ -63,33 +65,54 @@ public function __construct(Negotiator $negotiator, /* FormatsProviderInterface
public function onKernelRequest(GetResponseEvent $event): void
{
$request = $event->getRequest();
if (!($request->attributes->has('_api_resource_class') || $request->attributes->getBoolean('_api_respond', false) || $request->attributes->getBoolean('_graphql', false))) {
if (
!($request->attributes->has('_api_resource_class')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indented too much.

@@ -130,37 +153,29 @@ private function addRequestFormats(Request $request, array $formats): void
}

/**
* Populates the $mimeTypes property.
* Retries the flattened list of MIME types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retries -> Retrieves

*/
public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, /* FormatsProviderInterface */$formatsProvider, ResourceMetadataFactoryInterface $resourceMetadataFactory = null)
public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, $resourceMetadataFactory, ResourceMetadataFactoryInterface $legacyResourceMetadataFactory = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should remove the typehint for $legacyResourceMetadataFactory, right? And check that in the constructor body?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants