Problem/Motivation

Working on #2403307: RPC endpoints for user authentication: log in, check login status, log out I need to create a login resource. As discussed with @klausi, in this case, we only need to send the username/pass using post method and probably makes no sense to denormalize/normalize.

Proposed resolution

Avoid denormalization by default and fallback to decode otherwise

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

klausi’s picture

Status: Needs review » Postponed (maintainer needs more info)

Well, the deserialization should always happen, right? You just don't need to register a custom normalizer in the serializer chain, but you still want the JSON for example to be converted to arrays. So this should work as is, or do you get an exception?

marthinal’s picture

Yes, I need a serialization_class.

Uncaught PHP Exception ReflectionException: "Class  does not exist" at /Users/marthinal/workspace/sites/d8/core/modules/hal/src/Normalizer/NormalizerBase.php line 38

Trying to use directly jsonEncoder:

{"error":"Could not denormalize object of type Drupal\\serialization\\Encoder\\JsonEncoder, no supporting normalizer found."}

Not sure if I'm missing something...

marthinal’s picture

Status: Postponed (maintainer needs more info) » Needs review
klausi’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests
+++ b/core/modules/rest/src/RequestHandler.php
@@ -63,7 +63,13 @@ public function handle(RouteMatchInterface $route_match, Request $request, Route
         $definition = $resource->getPluginDefinition();
...
         try {
-          $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method));
+          if ($class) {
+            $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method));
+          }
+          // Avoid denormalization because we need to instantiate a class.
+          else {
+            $unserialized = $serializer->decode($received, $format, array('request_method' => $method));
+          }
         }

so this means that the serialization_class key is now optional in the plugin definition. We should add documentation to the RestResource.php annotation class what keys there are and that this one is optional.

And if it is optional you will get a PHP notice here, because it is not defined in $definition['serialization_class'], correct?

So we should check if serialization_class is set.

And we need a test case here. Either we add one to DBLogResource.php or we create our own simple rest_test module with the test plugin to check this.

Otherwise I do think that this approach is a good idea by just using the decode() method of the serializer.

marthinal’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
3.79 KB
5.13 KB

Using "serialization_class" annotation to reproduce the error.

The last submitted patch, 5: only-test-should-fail-2419825-5.patch, failed testing.

Wim Leers’s picture

Title: Avoid denormalization when not needed. » Avoid denormalization when not needed
Status: Needs review » Needs work
Issue tags: +Needs issue summary update

We should add documentation to the RestResource.php annotation class what keys there are and that this one is optional.

\Drupal\rest\Annotation\RestResource is not yet updated with this documentation. Marking NW for that.

The issue title & summary are also not very descriptive. It'd be great if you could make them more specific/descriptive.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

bigjim’s picture

rerolled for 8.1.x

bigjim’s picture

Wim Leers’s picture

Status: Needs work » Needs review

Marking Needs review so testbot tests it.

Wim Leers’s picture

Title: Avoid denormalization when not needed » Make serialization_class optional
Status: Needs review » Needs work

Thanks for picking this up again! :)

Here's a review. There are lots and lots of small problems with this patch. Fortunately, they're all super easy to fix :)

  1. +++ b/core/modules/rest/src/RequestHandler.php
    @@ -54,9 +54,15 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
    +          // If the plugin does not specify a serialization class just decode the received data.
    

    80 cols violation.

  2. +++ b/core/modules/rest/src/RequestHandler.php
    @@ -54,9 +54,15 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
    +          // Example: received JSON is decoded into a PHP array.
    

    This example is unclear.

  3. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +   * Tests that we must decode instead of deserialize.
    

    This sentence does not actually make sense.

  4. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +    // Enabling the service.
    

    No service is being enabled here.

  5. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +    $resources = [
    +      ['type' => 'serialization_test', 'method' => 'POST'],
    +    ];
    ...
    +    foreach ($resources as $resource) {
    

    There is only one resource. This foreach is overkill.

  6. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +    $format = 'json';
    ...
    +    $serialized = $this->container->get('serializer')->serialize(['foo'], 'hal_json');
    

    json vs. hal_json

  7. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +    $this->rebuildCache();
    

    I don't think this is necessary anymore.

  8. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +    // Add permission to anonymous user.
    ...
    +    // Create a JSON.
    ...
    +    // Post to the REST service to verify that the result is correct.
    

    These comments are all unnecessary. (And each contains grammatical errors.)

  9. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +104,40 @@ public function testAuthentication() {
    +    $this->assertResponse('200', 'HTTP response code is correct.');
    +    $this->assertResponseBody('"foo"', 'The Response Body is correct.');
    

    Both of these messages actually are more harmful than they help: the assert methods they use already provide far better messages.

Finally, #7 also still needs to be addressed.

The last submitted patch, 10: only-test-should-fail-2419825-9.patch, failed testing.

Wim Leers’s picture

Issue tags: +Needs change record
marthinal’s picture

Thank you Wim! yeah needs love. Finally I have time today to work a little bit on this :)

#10fails because we need to add the resource(Drupal\rest_test\Plugin\rest\resource\SerializationClassTestResource)

1) Done.

2) Removed.

3) Done.

4) Done.

5) Done.

6) Done.

7) Well, it is necessary. I need to understand why... but sure you have more knowledge about the cache :)

8) Done.

9) Done. Yes, we don't need to add these messages.

#7 still needs to be addressed.

dawehner’s picture

Looks great for me. We still need a change record though according to the issue.

Wim Leers’s picture

Status: Needs review » Needs work

Looks much, much better :) Very close to ready IMO. Just a few more small things, then this is RTBC.

  1. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +105,29 @@ public function testAuthentication() {
    +    $settings['serialization_test']['POST']['supported_formats'][] = 'json';
    +    $settings['serialization_test']['POST']['supported_auth'] = $this->defaultAuth;
    

    Why not use $this->enableService()?

  2. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +105,29 @@ public function testAuthentication() {
    +    $this->rebuildCache();
    

    This should not be necessary?

  3. +++ b/core/modules/rest/tests/modules/rest_test/src/Plugin/rest/resource/SerializationClassTestResource.php
    @@ -0,0 +1,32 @@
    +class SerializationClassTestResource extends ResourceBase {
    

    I'd call this NoSerializationClassTestResource.

The last submitted patch, 15: 2419825-15_only-test-should-fail.patch, failed testing.

dawehner’s picture

+++ b/core/modules/rest/src/Tests/ResourceTest.php
@@ -104,6 +105,29 @@ public function testAuthentication() {
+    $serialized = $this->container->get('serializer')->serialize(['foo'], 'json');
...
+    $this->assertResponseBody('"foo"');

+++ b/core/modules/rest/tests/modules/rest_test/src/Plugin/rest/resource/SerializationClassTestResource.php
@@ -0,0 +1,32 @@
+    return new ResourceResponse($array[0], 200, []);

IMHO we just just return the array, so that we check arrays as well

Wim Leers’s picture

#19++

marthinal’s picture

Ok! let's try again

17.1 Done

17.2 Removed

17.3 Done

19 Done

Thanks!!

marthinal’s picture

Issue tags: +neworleans2016

The last submitted patch, 21: 2419825-21-only-test-should-fail.patch, failed testing.

dawehner’s picture

Status: Needs review » Needs work

@marthinal
You uploaded the wrong patch ...

marthinal’s picture

Status: Needs work » Needs review
FileSize
4.34 KB

Oops yeah sorry :)

dawehner’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs issue summary update
+++ b/core/modules/rest/src/Tests/ResourceTest.php
@@ -104,6 +105,22 @@ public function testAuthentication() {
+    $this->assertResponse('200');

Nitpick: Its weird that we use '200' and not 200, but feel free to fix that on commit.

Wim Leers’s picture

  1. +++ b/core/modules/rest/src/Tests/ResourceTest.php
    @@ -104,6 +107,23 @@ public function testAuthentication() {
    +    $encoder = new JsonEncode();
    

    This is dead code, can be removed.

  2. +++ b/core/modules/rest/tests/modules/rest_test/src/Plugin/rest/resource/NoSerializationClassTestResource.php
    @@ -0,0 +1,32 @@
    +   * @param array $array
    

    Nit: s/$array/$data/

alexpott’s picture

@Wim Leers I can't see the code referred to in #27.1 - what am I missing.

marthinal’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
4.34 KB
1.51 KB

@alexpott #27.1 was fixed in #25 but appears in #21. Ok let's fix these nitpicks

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

This is perfect for me now

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Still needs a change record

Wim Leers’s picture

#28: Weird, sorry regarding #27.1, I have no idea how that happened!

#31: agreed, CR is missing. But … that points to another problem in REST's current code: \Drupal\rest\Annotation\RestResource doesn't list this serialization_class annotation attribute at all. I think this issue should fix that, and then immediately document it on the annotation class as being optional. If you want to see an example of how to do that, see \Drupal\Core\Annotation\Action.

Almost there! :)

dawehner’s picture

Wim Leers’s picture

Issue tags: -Needs change record

Do we still need this now that the user login functionality will no longer be a REST resource?

dawehner’s picture

Well, it won't be longer a blocker (as we already realized) but others kind of code might have the same problem.

Wim Leers’s picture

Category: Bug report » Feature request
Priority: Major » Normal

Fair.

However, that makes this a normal feature request IMO.

dawehner’s picture

Category: Feature request » Bug report

I would argue its a normal bug.

Wim Leers’s picture

Well, it won't be longer a blocker (as we already realized) but others kind of code might have the same problem.

Prescient words, because #2662284 is now blocked on this, see #2662284-55: Return complete entity after successful PATCH.

Wim Leers’s picture

Version: 8.1.x-dev » 8.2.x-dev

This is an API addition, should go into 8.2.

Wim Leers’s picture

All that's missing from this patch is an update to the annotation class, like I said in #32. Adding that brings it back to RTBC. My addition is mind-bogglingly trivial, so I think it's fine to re-RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: +8.2.0 release notes

Committed b3d0a73 and pushed to 8.2.x. Thanks!

Wim Leers’s picture

Wow, that was incredibly fast!

However, the commit has not yet been pushed. Could you do that? :) Thanks!

  • alexpott committed b3d0a73 on 8.2.x
    Issue #2419825 by marthinal, Wim Leers, bigjim, dawehner, klausi: Make...
andypost’s picture

+++ b/core/modules/rest/src/Annotation/RestResource.php
@@ -38,4 +38,11 @@ class RestResource extends Plugin {
+   * The serialization class to deserialize serialized data into.
...
+  public $serialization_class;

looks that backportable to 8.1

Wim Leers’s picture

Issue tags: +API addition

#44: but it's an API addition.

It wouldn't harm 8.1 in any way, but we don't do API additions to the current version unless absolutely necessary.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.