API Platform - Which approach should I use for creating custom operation without entity

陌路散爱 提交于 2020-05-10 18:51:27

问题


I'm new to API Platform. I think it's great but I cannot find any example how to create custom endpoint that isn't based on any entity. There are a lot of examples based on an entity and usually they are all about CRUD. But what about custom operations?

I need to create custom search through database with some custom parameters which aren't related to any entity. E.g. I want to receive POST request something like this:

{
   "from": "Paris",
   "to": "Berlin"
}

This data isn't saved to db and I haven't entity for it. After I receive this data, there should be a lot of business logic including db queries through a lot of db tables and also getting data from external sources. Then, after the business logic is finished, I want to return back result which is also custom and isn't related to any entity. E.g.

{
    "flights": [/* a lot of json data*/],
    "airports": [/* a lot of json data*/],
    "cities": [/* a lot of json data*/],
    .......
}

So, I think I'm not the only on who does something similar. But I really cannot find a solution or best practices how to do this. In the documentation I've found at least three approaches and I cannot implement none of them. The best one, I guess the most suitable for me it is using Custom Operations and Controllers. But documentation says this one is not recommended. Also I think I should use DTOs for request and response, but for this approach I'm not sure I can use them.

The second one I found it's using Data Transfer Objects, but this approach requires an entity. According to the documentation, I should use DTOs and DataTransformers to convert DTO to an Entity. But I don't need entity, I don't need save it to db. I want just handle received DTO on my own.

The third one I guess it is using Data Providers, but I'm not sure it is suitable for my requirements.

So, the main question is which approach or best practice should I use to implement custom operation which isn't related to any entity. And it will be great use DTOs for request and response.


回答1:


You are not forced to use entities. Classes that are marked with @ApiResource annotation may not be entities. Actually, if your application is smarter than basic CRUD you should avoid marking entities as ApiResource.

Since you want to use POST HTTP method (which is for creating resource items) you can do something like this.

1) Define class describing search fields and which will be your @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) Define DTO that will represent the output

<?php
// src/Dto/SearchResult.php

namespace App\Dto;

class SearchResult
{
    public $flights;
    public $airports;
    public $cities;
}

3) Create class that will inplement DataPersisterInterface for handling business logic. It will be called by framework because you make POST request.

<?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
    }
}

That way you will recieve results based on request.



来源:https://stackoverflow.com/questions/58398351/api-platform-which-approach-should-i-use-for-creating-custom-operation-without

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