How to write custom endpoints with parameters not related to any specific entity

旧时模样 提交于 2021-02-03 21:32:42

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!