Api-平台:使用PUT创建资源
Api-Platform: using PUT for creating resources
我想使用 PUT 方法创建资源。它们由 UUID 标识,并且由于可以在客户端创建 UUID,我想启用以下行为:
- PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 如果此资源存在,请更新它
- PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 如果此资源不存在,请创建它
可以通过实施 ItemDataProviderInterface
/ RestrictedDataProviderInterface
来实现。
但是,我的资源实际上是一个子资源,所以假设我想创建一个新的 Book
来引用现有的 Author
.
我的构造函数如下所示:
/**
* Book constructor
*/
public function __construct(Author $author, string $uuid) {
$this->author = $author;
$this->id = $uuid;
}
但我不知道如何从我的 BookItemProvider
访问 Author
实体(在请求正文中提供)。
有什么想法吗?
在 API 平台中,项目创建时应发生的许多事情都基于请求的类型。改起来会很麻烦。
这里有 2 种可能性来制作您想要的东西。
首先,你可以考虑做一个自定义路由,使用你自己的逻辑。如果你这样做,你可能会很高兴知道在你的自定义路由上使用选项 _api_resource_class
将启用 APIPlaform 的一些听众并避免你做一些工作。
第二种解决方案,例如,如果您需要全局行为,则覆盖 API 平台。您的主要问题是 ApiPlatform 的 ReadListener
如果找不到您的资源,它将抛出异常。此代码可能不起作用,但这里是如何覆盖此行为的想法:
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());
}
}
}
并且您需要指定一个配置来将您的 class 声明为服务装饰器:
services:
CustomReadListener:
decorate: api_platform.listener.request.read
arguments:
- "@CustomReadListener.inner"
希望对您有所帮助。 :)
更多信息:
我想使用 PUT 方法创建资源。它们由 UUID 标识,并且由于可以在客户端创建 UUID,我想启用以下行为:
- PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 如果此资源存在,请更新它
- PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 如果此资源不存在,请创建它
可以通过实施 ItemDataProviderInterface
/ RestrictedDataProviderInterface
来实现。
但是,我的资源实际上是一个子资源,所以假设我想创建一个新的 Book
来引用现有的 Author
.
我的构造函数如下所示:
/**
* Book constructor
*/
public function __construct(Author $author, string $uuid) {
$this->author = $author;
$this->id = $uuid;
}
但我不知道如何从我的 BookItemProvider
访问 Author
实体(在请求正文中提供)。
有什么想法吗?
在 API 平台中,项目创建时应发生的许多事情都基于请求的类型。改起来会很麻烦。
这里有 2 种可能性来制作您想要的东西。
首先,你可以考虑做一个自定义路由,使用你自己的逻辑。如果你这样做,你可能会很高兴知道在你的自定义路由上使用选项 _api_resource_class
将启用 APIPlaform 的一些听众并避免你做一些工作。
第二种解决方案,例如,如果您需要全局行为,则覆盖 API 平台。您的主要问题是 ApiPlatform 的 ReadListener
如果找不到您的资源,它将抛出异常。此代码可能不起作用,但这里是如何覆盖此行为的想法:
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());
}
}
}
并且您需要指定一个配置来将您的 class 声明为服务装饰器:
services:
CustomReadListener:
decorate: api_platform.listener.request.read
arguments:
- "@CustomReadListener.inner"
希望对您有所帮助。 :)
更多信息: