问题
I'm trying to write custom GET endpoints, which must have one or more custom parameters, but not built on top of specific entity.
Something like: /assets/{device_id}/{scene_id}/{maybe_other_param}
which I imagine to be just own controller class, in which I do something, calculate values from input, read some data manually and return array of entities. What I only get is an Asset entity, but it requires {device} and {scene} to be properties of this entity...
I don't want this to work as exposed entity with filter by its properties, I just need simple endpoint seen in API, as normal custom controller which takes some params, do stuff and return json.
It sounds like simple thing, but I read tons of documentation and examples and still didn't find anything. Is this even possible in API-platform?
回答1:
If you want the parameters from the path to be passed to your Controller directly you need to configure the operation with "read"=false. Here is the simpelest Asset resource i could make to work with such a collection operation:
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use App\Controller\GetAssetCollectionByPathParams;
/**
* @ApiResource(
* collectionOperations={
* "get",
* "get_by_path_params"={
* "method"="GET",
* "controller"=GetAssetCollectionByPathParams::class,
* "path"="/assets/{device_id}/{scene_id}/{maybe_other_param?}",
* "read"=false,
* "pagination_enabled"=false,
* "openapi_context"={
* "summary"="Get by path parameters",
* "parameters"={
* {
* "name" = "device_id",
* "in" = "path",
* "required" = true,
* "type" = "integer"
* },
* {
* "name" = "scene_id",
* "in" = "path",
* "required" = true,
* "type" = "string"
* },
* {
* "name" = "maybe_other_param",
* "in" = "path",
* "required" = false,
* "type" = "string"
* }
* }
* }
* }
* },
* itemOperations={
* "get"
* }
* )
*/
class Asset
{
/** @var string */
public $description;
/**
* @return int
* @ApiProperty(identifier=true)
*/
public function getId()
{
return time();
}
}
I tested it with the following Contoller class:
namespace App\Controller;
use App\Entity\Asset;
class GetAssetCollectionByPathParams
{
/**
* @return Asset[]
*/
public function __invoke($device_id, $scene_id, $maybe_other_param=null) :array
{
$result = new Asset();
$result->description = "GetAssetCollectionByPathParams result for device_id: $device_id, scene_id: $scene_id, maybe_other_param: $maybe_other_param";
return [$result];
}
}
Also works for GET item operations. With collection operations whose output is a resource don't remove any of the default "get" operations from otherwise the IriConverter can not produce the necessary iri's. If you don't want that you must output a DTO or so that is not a resource and configure output= to the class of the output. Then you need to correct the swagger docs for that too, see chapter9-api branch of my tutorial for an example with a collection operaton. For a POST operation see my answer to this question.
来源:https://stackoverflow.com/questions/56589694/how-to-write-custom-endpoints-with-parameters-not-related-to-any-specific-entity