Api-Platform:使用 PUT 创建资源 [英] Api-Platform: using PUT for creating resources

查看:19
本文介绍了Api-Platform:使用 PUT 创建资源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 PUT 方法来创建资源.它们由 UUID 标识,并且由于可以在客户端创建 UUID,因此我想启用以下行为:

I would like to use the PUT method for creating resources. They are identified by an UUID, and since it is possible to create UUIDs on the client side, I would like to enable the following behaviour:

  • 在 PUT/api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 上,如果此资源存在,请更新它
  • 在 PUT/api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 上,如果此资源不存在,则创建它

可以通过实现 ItemDataProviderInterface/RestrictedDataProviderInterface 来实现这一点.

It's possible to achieve this by implementing an ItemDataProviderInterface / RestrictedDataProviderInterface.

然而,我的资源实际上是一个子资源,所以假设我想创建一个新的 Book 引用现有的 Author.

However, my resource is actually a subresource, so let's say I want to create a new Book which references an existing Author.

我的构造函数如下所示:

My constructor looks like this:

/**
 * Book constructor
 */
public function __construct(Author $author, string $uuid) {
    $this->author = $author;
    $this->id = $uuid;
}

但我不知道如何从我的 BookItemProvider 访问 Author 实体(在请求正文中提供).

But I don't know how to access the Author entity (provided in the request body) from my BookItemProvider.

有什么想法吗?

推荐答案

在 API 平台中,项目创建时应该发生的许多事情都是基于请求的类型.改变会很复杂.

In API Platform many things that should occur on item creation is based on the kind of request it is. It would be complicated to change.

这里有 2 种可能性来制作您想要的东西.

Here are 2 possibilities to make what you want.

首先,您可以考虑做一个自定义路由并使用您自己的逻辑.如果您这样做,您可能会很高兴知道在您的自定义路由上使用选项 _api_resource_class 将启用 APIPlaform 的一些侦听器并避免您做一些工作.

First, you may consider to do a custom route and use your own logic. If you do it you will probably be happy to know that using the option _api_resource_class on your custom route will enable some listeners of APIPlaform and avoid you some work.

例如,如果您需要全局行为,则第二种解决方案是覆盖 API 平台.您的主要问题是 ApiPlatform 的 ReadListener ,如果找不到您的资源,它将抛出异常.此代码可能不起作用,但这里是如何覆盖此行为的想法:

The second solution, if you need global behavior for example, is to override API Platform. Your main problem for this is the ReadListener of ApiPlatform that will throw an exception if it can't found your resource. This code may not work but here is the idea of how to override this behavior:

class CustomReadListener
{
    private $decoratedListener;

    public function __construct($decoratedListener)
    {
        $this->decoratedListener = $decoratedListener;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        try {
            $this->decoratedListener->onKernelRequest($event);
        } catch (NotFoundHttpException $e) {
            // Don't forget to throw the exception if the http method isn't PUT 
            // else you're gonna break the 404 errors
            $request = $event->getRequest();

            if (Request::METHOD_PUT !== $request->getMethod()) {
                throw $e;
            }

            // 2 solutions here:

            // 1st is doing nothing except add the id inside request data
            // so the deserializer listener will be able to build your object


            // 2nd is to build the object, here is a possible implementation

            // The resource class is stored in this property
            $resourceClass = $request->attributes->get('_api_resource_class');

            // You may want to use a factory? Do your magic.
            $request->attributes->set('data', new $resourceClass());
        }
    }
}

并且您需要指定一个配置来将您的类声明为服务装饰器:

And you need to specify a configuration to declare your class as service decorator:

services:
    CustomReadListener:
        decorate: api_platform.listener.request.read
        arguments:
            - "@CustomReadListener.inner"

希望有帮助.:)

更多信息:

这篇关于Api-Platform:使用 PUT 创建资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆