You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are times (as mentioned several times throughout API Platform) when you want to use a separate models for different endpoints for a specific resource.
I've found for most of my entities that aren't simple CRUD, I typically need to overwrite 1-3 endpoints so that I can setup custom services for handling those endpoints which handle the business logic in creation. Typically it's the POST, DELETE, and PUT endpoints that I'd end up having a special service manage for a specific entity (most of the time, I just need to override POST).
My current way of managing this works, but it has a bunch boilerplate which is needed to allow API platform to properly generate the swagger documentation.
Then, I have a custom data persister that looks like the following:
<?phpnamespaceApp\DataPersister;
useApiPlatform\Core\DataPersister\DataPersisterInterface;
useApp\DTO;
useApp\Exception\RequestHandlerNotFound;
useApp\Service;
usePsr\Container\ContainerInterface;
useSymfony\Component\DependencyInjection\ServiceSubscriberInterface;
class AppDataPersister implements DataPersisterInterface, ServiceSubscriberInterface
{
private$container;
private$persister;
publicfunction__construct(ContainerInterface$container, DataPersisterInterface$persister) {
$this->container = $container;
$this->persister = $persister;
}
/** * Is the data supported by the persister? * * @param mixed $data * * @return bool */publicfunctionsupports($data): bool {
return (is_object($data) && $this->container->has(get_class($data))) || $this->persister->supports($data);
}
/** * Persists the data. * * @param mixed $data * * @return object|void Void will not be supported in API Platform 3, an object should always be returned */publicfunctionpersist($req) {
$requestClass = get_class($req);
if (!$this->container->has($requestClass) && !$this->persister->supports($req)) {
thrownewRequestHandlerNotFound($requestClass);
} elseif (!$this->container->has($requestClass)) {
return$this->persister->persist($req);
}
$handleReq = $this->container->get($requestClass);
return$handleReq($req);
}
/** * Removes the data. * * @param mixed $data */publicfunctionremove($data) {
return$this->persister->remove($data);
}
publicstaticfunctiongetSubscribedServices() {
return [
DTO\CapturePaymentRequest::class => Service\CapturePayment::class,
];
}
}
Now, this system works pretty good, but it's quite complicated and hard to explain to new devs on what's going on because it's a lot of boilerplate to implement something straight forward.
For the record, i'm pretty sure I could ditch the AppDataPersister, and just use a custom controller action which then calls the service, but that also seemed like overkill in regards to creating a custom controller class along with the service class.
Proposed Solution
I think an easy solution to this would be to extend operation schema in config to allow a custom resource model:
Then, we could add (likely in a separate scope of work), I could add a MessageBusDataPersister that routes those entities into the message bus and we could just piggy back off of the MessageBus's awesome implementation for tagging handlers.
Proof of Concept
I was able to get a basic PoC working by doing the following in my resource yaml config:
App\Entity\CapturedPayment:
collectionOperations:
get: ~post:
defaults:
_api_resource_class: SG\Svc\SalesChannel\Core\DTO\Payment\CapturePaymentRequestswagger_context:
parameters:
- in: bodyname: capturedPaymentRequestrequired: trueschema: { $ref: "#/definitions/CapturePaymentRequest" }# This is needed so that the swagger docs gen to add this into swagger modelsApp\DTO\CapturePaymentRequest:
itemOperations: []collectionOperations:
post: ~
Would like to submit a PR to the core because the changes are pretty minor and I think offer a great deal of ease when configuring operations with different resource classes.
There are times (as mentioned several times throughout API Platform) when you want to use a separate models for different endpoints for a specific resource.
I've found for most of my entities that aren't simple CRUD, I typically need to overwrite 1-3 endpoints so that I can setup custom services for handling those endpoints which handle the business logic in creation. Typically it's the POST, DELETE, and PUT endpoints that I'd end up having a special service manage for a specific entity (most of the time, I just need to override POST).
My current way of managing this works, but it has a bunch boilerplate which is needed to allow API platform to properly generate the swagger documentation.
Then, I have a custom data persister that looks like the following:
Now, this system works pretty good, but it's quite complicated and hard to explain to new devs on what's going on because it's a lot of boilerplate to implement something straight forward.
For the record, i'm pretty sure I could ditch the AppDataPersister, and just use a custom controller action which then calls the service, but that also seemed like overkill in regards to creating a custom controller class along with the service class.
Proposed Solution
I think an easy solution to this would be to extend operation schema in config to allow a custom resource model:
Then, we could add (likely in a separate scope of work), I could add a
MessageBusDataPersister
that routes those entities into the message bus and we could just piggy back off of the MessageBus's awesome implementation for tagging handlers.Proof of Concept
I was able to get a basic PoC working by doing the following in my resource yaml config:
This works pretty well, but you need to update https://github.com/api-platform/core/blob/master/src/Bridge/Symfony/Routing/ApiLoader.php#L212 to allow the
$options['defaults']
to override the defaults provided by API Platform (using array_merge would fix that issue).The text was updated successfully, but these errors were encountered: