Skip to content
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

Add a flag to disable all request listeners #909

Merged
merged 6 commits into from
Feb 12, 2017

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Jan 12, 2017

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #880, #781, #782, #805
License MIT
Doc PR todo

To disable all API Platform request listeners (read, deserialize and validate), you have to create a new request attribute (for instance by setting the defaults key in a route definition) called api_request to false.

ping @lyrixx, @kbsali, @gpenverne.

@@ -45,13 +45,17 @@ public function __construct(ValidatorInterface $validator, ResourceMetadataFacto
public function onKernelView(GetResponseForControllerResultEvent $event)
{
$request = $event->getRequest();
if ($request->isMethodSafe(false) || $request->isMethod(Request::METHOD_DELETE)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This change isn't really related, but is a minor performance improvement.

@lyrixx
Copy link
Contributor

lyrixx commented Jan 12, 2017

Actually, in my context, I did not want to remove all listeners. juste the deserialization. I guess you will understand better my use case will "real code"

    /**
     * @Route(
     *     name="api_envs_add_member",
     *     path="/api/v2/envs/{env}/members",
     * )
     * @Method("POST")
     * @Security("is_granted('CONFIGURE', env)")
     */
    public function addMemberAction(Request $request, AbstractEnv $env)
    {
        $envMember = new EnvMember($this->getUser(), $env);

        $form = $this->container->get('form.factory')
            ->createNamed('', EnvMemberType::class, $envMember)
            ->handleRequest($request)
        ;

        $violations = $this->get('validator')->validate($envMember);

        if (0 !== count($violations)) {
            // use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
            throw new ValidationException($violations);
        }

        $this->get('profiler.server_sharing')->approve($this->getUser(), $env, $envMember->getEmail());

        // Fake until https://github.com/api-platform/core/issues/880 is fixed
        $request->attributes->set('_api_resource_class', AbstractEnv::class);
        $request->attributes->set('_api_item_operation_name', 'add member');

        return $env;
    }

@dunglas
Copy link
Member Author

dunglas commented Jan 12, 2017

It removes only "request listeners" (write listeners), so it will do the trick (the serialization process will still work).

@dunglas
Copy link
Member Author

dunglas commented Jan 12, 2017

Unrelated but:

        // Fake until https://github.com/api-platform/core/issues/880 is fixed
        $request->attributes->set('_api_resource_class', AbstractEnv::class);
        $request->attributes->set('_api_item_operation_name', 'add member');

It works when attributes are set manually but not when the router sets them? Weird.

@lyrixx
Copy link
Contributor

lyrixx commented Jan 12, 2017

It works when attributes are set manually but not when the router sets them? Weird.

Actually it's a big HACK

  1. I get some data, in JSON that is not related to the Env (I mean, it's not a serialization of an env)
  2. I process this thaht
  3. I tell to API platfrom it an Env
  4. I return the env ;)

so in practice

curl -X POST /../env-id/members -d "{email="xxx", ...}"
return the env serialized ;)

@dunglas
Copy link
Member Author

dunglas commented Jan 12, 2017

Got it, sorry about that. This PR should fix your issue.

Copy link
Contributor

@Simperfit Simperfit left a comment

Choose a reason for hiding this comment

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

If you have some time to add that 0.05% of coverage , coveralls will be happy :).

if (null === $apiRequest = $request->attributes->get('_api_request')) {
$result['request'] = true;
} else {
$result['request'] = (bool) $apiRequest;
Copy link
Contributor

Choose a reason for hiding this comment

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

What could be the value of this ? true / false or just false ?

Copy link
Member Author

Choose a reason for hiding this comment

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

true / false, 1 / 0 (when using a route to define the attribute).

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like this cast. It lets through more than what we want to support. We should use an explicit test.

Copy link
Member Author

@dunglas dunglas Jan 25, 2017

Choose a reason for hiding this comment

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

Yes me too but the cast is mandatory to support the routing component < 3.2 (before this version, types wasn't supported and the user was able to put anything that can be casted to a boolean in such cases).

@teohhanhui
Copy link
Contributor

I'm -1 because one could just create custom routes and controllers / actions outside of the API Platform system altogether. This is an unwelcome hack.

@dunglas
Copy link
Member Author

dunglas commented Jan 13, 2017

It doesn't sound like a hack to me. What do you suggest to fix the issue raised by @lyrixx?
If it's outside the API Platform, it's not available in the generated docs (including the Hydra one).

@dunglas
Copy link
Member Author

dunglas commented Jan 20, 2017

ping @teohhanhui, I would like to merge this asap.

@teohhanhui
Copy link
Contributor

I'm still -1. If we proceed with this, sooner or later we'll be adding _api_read, _api_deserialize, _api_validate, _api_write, _api_serialize, _api_response etc.

This is a misfeature. If we want to allow for more flexibility, we should add extension points (if they are not already available) and/or the possibility to decorate the listeners. For example, I'm able to do what was requested in #781 by decorating the DeserializeListener. I suspect #880 can use a similar solution.

@dunglas
Copy link
Member Author

dunglas commented Jan 24, 2017

@teohhanhui wanting to deal with the request "manually" without any preprocessing done by the framework is a very common use case and one of the most wanted feature (see the list of referenced tickets). Indeed it can already be done using extension points, but having to decorate services to do a so common operation is too much work for the developper IMO.
And it's not consistent, because we already allow to skip the post processing (using api_respond), so we need the same feature for the preprocessing.

I'm still -1. If we proceed with this, sooner or later we'll be adding _api_read, _api_deserialize, _api_validate, _api_write, _api_serialize, _api_response etc.

It's not gonna to happen. The point here is to skip entirely the preprocessing.

@teohhanhui
Copy link
Contributor

Uhh, okay. I didn't notice there's api_respond. It should be fine then...

if (null === $apiRequest = $request->attributes->get('_api_request')) {
$result['request'] = true;
} else {
$result['request'] = (bool) $apiRequest;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like this cast. It lets through more than what we want to support. We should use an explicit test.

@@ -61,6 +61,24 @@ public function testDoNotCallWhenRequestNotManaged()
$listener->onKernelRequest($eventProphecy->reveal());
}

public function testDoNotCallWhenRequestRequestIsFalse()
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps testDoNotCallWhenRequestSkipRequestProcessing?

Copy link
Contributor

Choose a reason for hiding this comment

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

testDoNotCallWhenRequestSkipProcessing seems more accurate

Copy link
Contributor

Choose a reason for hiding this comment

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

It's only request processing that's being skipped, not all processing. In a similar fashion we could say "skip response processing".

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking more about it, we have api_respond, not api_response. So maybe it should be api_receive? @dunglas

Copy link
Contributor

Choose a reason for hiding this comment

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

And the corresponding term would be "skip receive"?

Copy link
Member Author

Choose a reason for hiding this comment

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

api_receive

Love it. I'll update the PR.

@@ -39,6 +39,24 @@ public function testNotAnApiPlatformRequest()
$listener->onKernelRequest($event->reveal());
}

public function testRequestIsFalse()
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 should try to standardize the test function names (like above)...

@dunglas
Copy link
Member Author

dunglas commented Feb 11, 2017

Attribute renamed _api_receive and new functional and unit tests added.

@dunglas dunglas merged commit d65c84b into api-platform:master Feb 12, 2017
@dunglas dunglas deleted the disable_request_listener branch February 12, 2017 18:33
soyuka pushed a commit to soyuka/core that referenced this pull request Mar 7, 2017
soyuka pushed a commit to soyuka/core that referenced this pull request Mar 13, 2017
soyuka pushed a commit to teohhanhui/api-platform-core that referenced this pull request Mar 16, 2017
hoangnd25 pushed a commit to hoangnd25/core that referenced this pull request Feb 23, 2018
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.

None yet

5 participants