Api-Platform:使用 PUT 创建资源 [英] Api-Platform: using PUT for creating resources
问题描述
我想使用 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"
希望有帮助.:)
更多信息:
- 关于事件调度器和内核事件的信息:http://symfony.com/doc/current/components/event_dispatcher.html
- ApiPlatform 自定义操作:https://api-platform.com/docs/core/operations#creating-custom-operations-and-controllers
- Symfony 服务修饰:https://symfony.com/doc/current/service_container/service_decoration.html
这篇关于Api-Platform:使用 PUT 创建资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!