Платформа API - какой подход следует использовать для создания настраиваемой операции без сущности - PullRequest
3 голосов
/ 15 октября 2019

Я новичок в платформе API. Я думаю, что это здорово, но я не могу найти пример того, как создать пользовательскую конечную точку, которая не основана на какой-либо сущности. Есть много примеров, основанных на сущности, и обычно они все о CRUD. Но как насчет пользовательских операций?

Мне нужно создать пользовательский поиск по базе данных с некоторыми пользовательскими параметрами, которые не связаны ни с одним объектом. Например, я хочу получить POST-запрос примерно так:

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

Эти данные не сохраняются в БД, и у меня нет сущности для них. После того, как я получу эти данные, должно появиться много бизнес-логики, включая запросы к базе данных через множество таблиц базы данных, а также получение данных из внешних источников. Затем, после завершения бизнес-логики, я хочу вернуть обратный результат, который также является нестандартным и не связан с какой-либо сущностью. Например,

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

Итак, я думаю, что я не единственный, кто делает что-то подобное. Но я действительно не могу найти решение или лучшие практики, как это сделать. В документации я нашел как минимум три подхода и не могу реализовать ни один из них. Лучшее, я думаю, самое подходящее для меня это использование пользовательских операций и контроллеров. Но документация говорит, что это не рекомендуется. Также я думаю, что я должен использовать DTO для запроса и ответа, но для этого подхода я не уверен, что смогу их использовать.

Второй, который я обнаружил, - это использование объектов передачи данных, но для этого подхода требуется сущность. Согласно документации, я должен использовать DTO и DataTransformers для преобразования DTO в сущность. Но мне не нужна сущность, мне не нужно сохранять ее в БД. Я хочу просто обработать полученный DTO самостоятельно.

Третий, я полагаю, использует провайдеров данных, но я не уверен, что он подходит для моих требований.

Итак, главноеВопрос заключается в том, какой подход или передовой опыт следует использовать для реализации пользовательских операций, не связанных с какими-либо объектами. И будет здорово использовать DTO для запросов и ответов.

1 Ответ

1 голос
/ 20 октября 2019

Вы не обязаны использовать сущности. Классы, помеченные @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
    }
}

Таким образом, вы получите результаты на основе запроса.

...