简体   繁体   中英

Symfony4 - Where process the payload in restful api

I have been working on a restful api, I would like to know where should I process the payload after been validated. Right now it look something like this:

// src/Controller/ExampleController.php
public function create(Request $request, EntityManagerInterface $manager)
{
    // the getPayload gonna return a object representing my data
    // already validate, ready to be processed
    $data = $this->getPayload()

    $exampleEntity = new ExampleEntity();
    $exampleEntity
        ->setUser($this->getUser())
        ->setBook($data->book);
    $manager->persist($exampleEntity);
    $manager->flush();

    return new JsonResponse($example->getResult());
}

I was adviced to create a service to process the data and don't use direct in the controller. I actually like to separate the data outside the controller, but then should I create a service for each controller? something like this:

// src/Controller/SomeController.php
public function create(Request $request, \App\Service\Example $example)
{
    // the getPayload gonna return a object representing my data
    // already validate, ready to be processed
    $data = $this->getPayload()
    $example->setPayload($data);
    $example->process();

    return new JsonResponse($example->getResult());
}

I have other question, should I validate identifiers, for example if I receive a json body passing the id of a book, if I create a new constraint to verify if the book exist it would require a query in the database (because i'm validating the payload automatically before it gets int he controller) and one more query later to actually create the relation. Example:

// src/Controller/ExampleController.php
public function create(
    Request $request,
    ExampleReposiry $repository,
    EntityManagerInterface $manager)
{
    // the getPayload gonna return a object representing my data
    // already validate, ready to be processed
    $data = $this->getPayload()

    $exampleEntity = new ExampleEntity();
    $exampleEntity
        ->setUser($this->getUser())
        // $data->book is only the id, not the actually object book
        // this is the second time query for the object, the fist
        // time was inside the custom constraint that validate
        // to see if the id pass is valid.
        ->setBook($repository->findBy(['id' => $data->book]));
    $manager->persist($exampleEntity);
    $manager->flush();

    return new JsonResponse($example->getResult());
}

Or instead of that I just assume that the id of the book pass is valid and if not I just throw an Exception?

The post that I follow to validate automatically the data here

I was adviced to create a service to process the data and don't use direct in the controller. I actually like to separate the data outside the controller, but then should I create a service for each controller?

Or instead of that I just assume that the id of the book pass is valid and if not I just throw an Exception?

I would separate responsibilities as follows.

  1. Create a ExampleService class (where business logic takes place) and inject it into ExampleController .
  2. Pass you validated data-set to ExampleService class.
  3. Check if the id of the book in DB. Throw an exception otherwise.
  4. Create a ExampleFactory class (where data mapping takes place) and inject it into ExampleService .
  5. Pass your data-set to ExampleFactory so that it returns ExampleEntity instance.
  6. Call persist and flush on ExampleEntity instance. Assuming that you already injected ExampleRepository class into ExampleService class.

Then do whatever else you need to do and return Response::HTTP_CREATED in ExampleController .

This was my implementation base on what @BentCoder answered. After pass the whole day at work thinking factory or no factory ? I end up trying use factory pattern because:

  • it's smart follow advice of more experienced programmers (or give a try at least)
  • better understanding of a pattern
  • try out new things (it's a side project so it's ok mess up)

     // src/Controller/ExampleController.php public function create(\\App\\Service\\Example $exampleService) { $exampleService->process($this->getPayload()); // .. do something } // src/Service/Example.php public function process(App\\Model\\ExampleInterface $data) { // factory was receive via dependency injection in the constructor $objects = $this->factory->create($data); // .. do something } // src/Model/Example/Create.php class Create implements App\\Model\\ExampleInterface { public $property1; public $property2; } // src/Model/Example/Update.php class Update implements App\\Model\\ExampleInterface { public $property2; } // src/Factory/ExampleFactory.php public function create(App\\Model\\ExampleInterface $data) { if ($data instanceof App\\Model\\Example\\Create::class) ( // .. return a array of instantiated object } elseif ($data instanceof App\\Model\\Example\\Update::class) { // .. returm only one object } } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM