我是API平台的新手。我认为这很棒,但我找不到如何创建不基于任何实体的自定义终结点的示例。有很多基于实体的示例,通常都与CRUD有关。但是自定义操作呢?
我需要使用一些与任何实体都不相关的自定义参数来通过数据库创建自定义搜索。例如。我想收到类似这样的POST请求:
{
"from": "Paris",
"to": "Berlin"
}
此数据未保存到db,因此我没有实体。收到此数据后,应该有很多业务逻辑,包括通过许多数据库表进行数据库查询,以及从外部源获取数据。然后,在业务逻辑完成之后,我想返回的结果也是自定义的,并且与任何实体都不相关。例如:
{
"flights": [/* a lot of json data*/],
"airports": [/* a lot of json data*/],
"cities": [/* a lot of json data*/],
.......
}
所以,我认为我并不是唯一从事类似工作的人。但是我真的找不到解决方案或最佳实践。在文档中,我至少找到了三种方法,但我都无法实现。最好的,我想最适合我的是使用自定义操作和控制器。但是文档说不建议这样做。另外,我认为我应该使用DTO进行请求和响应,但是对于这种方法,我不确定是否可以使用它们。
第二个,我发现它正在使用数据传输对象,但是这种方法需要一个实体。根据文档,我应该使用DTO和DataTransformers将DTO转换为实体。但是我不需要实体,也不需要将其保存到数据库。我只想自己处理收到的DTO。
我猜第三个正在使用数据提供程序,但我不确定它是否适合我的要求。
因此,主要问题是我应该使用哪种方法或最佳实践来实现与任何实体都不相关的自定义操作。 DTO用于请求和响应将非常有用。
您不会被迫使用实体。用@ApiResource
批注标记的类可能不是实体。实际上,如果您的应用程序比基本CRUD聪明,则应避免将实体标记为ApiResource。
由于您要使用POST HTTP方法(用于创建资源项目),您可以执行以下操作。
1)定义描述搜索字段的类,它将作为您的@ApiResource
<?php
// src/ApiResource/Search.php
namespace App\ApiResource;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Action\NotFoundAction;
use ApiPlatform\Core\Annotation\ApiProperty;
use App\Dto\SearchResult;
/**
* @ApiResource(
* itemOperations={
* "get"={
* "controller"=NotFoundAction::class,
* "read"=true,
* "output"=false,
* },
* },
* output=SearchResult::class
* )
*/
class Search
{
/**
* @var string
* @ApiProperty(identifier=true)
*/
public $from;
/** @var string */
public $to;
}
2)定义将代表输出的DTO
<?php
// src/Dto/SearchResult.php
namespace App\Dto;
class SearchResult
{
public $flights;
public $airports;
public $cities;
}
3)创建一个将填充DataPersisterInterface
的类来处理业务逻辑。因为您发出POST请求,所以框架会调用它。
<?php
// src/DataPersister/SearchService.php
declare(strict_types=1);
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use App\Dto\SearchResult;
use App\ApiResource\Search;
final class SearchService implements DataPersisterInterface
{
public function supports($data): bool
{
return $data instanceof Search;
}
public function persist($data)
{
// here you have access to your request via $data
$output = new SearchResult();
$output->flights = ['a lot of json data'];
$output->airports = ['a lot of json data'];
$output->cities = ['inputData' => $data];
return $output;
}
public function remove($data)
{
// this method just need to be presented
}
}
这样,您将根据请求接收结果。