2

This top-ranking Stackoverflow answer from 10 years ago suggests using POST /users/:user_id/reset_password to initiate a password reset.

I know the API platform recommends against using custom operations. The docs page for the Symfony Messenger integration uses a ResetPasswordRequest entity (with a username field). That makes sense to me. 

Say I have a User and Notification entity and maybe a joined UserNotification (with a hasRead) entity as well. I want to expose an endpoint on my API to mark all the notifications older than a month as read. So I might make a ClearOldNotification entity, again with a username field.

Another example might be I want a report showing Customers that haven't been contacted due to some criteria. So I want to join the tables in the server and return a custom JSON data object. Again I could make a CustomerNoContact entity.

The issue I see is that I now have a distinction between pure entities, like a User or Product, as opposed to these service type entities.

  • Is this method of making individual entities classes for actions the recommended, best practice for Symfony and API Platform?
  • Should I be name-spacing (or something) these entities differently within my app to distinguish them?
  • I could imagine on a really large and complex application you could have hundreds of these service entities, compared to the pure entities. Is that expected or desired?
  • Can anyone recommend some good resources on this pattern?
Rowan Parker
  • 794
  • 2
  • 7
  • 18
  • IMHO service type Entities are workarounds for limitations imposed by Api Platform. But other solution are available: As suggested in the Design Considerations [a POPO can be used as a resource](https://stackoverflow.com/questions/64744246/operation-without-entity). And/or a [DTO](https://stackoverflow.com/questions/65847821/exposing-a-model-without-any-routes) or [a view model](https://github.com/metaclass-nl/tutorial-api-platform/blob/chapter9-api) as output. – MetaClass Mar 15 '21 at 16:34

1 Answers1

2

You're asking for a best practice for two different use cases. Let's break it down:

ClearOldNotification

I think you've already found the solution: using Messenger. As you've read, there is an example in the documentation for this use case:

#[ApiResource(collectionOperations: [
        "post", "get", "delete",
        "reset_password" => ["status" => 202, "messenger" => "input", "input" => ResetPasswordRequest::class, "output" => false, "method" => "POST", "path" => "/users/reset_password"]
    ]
)]
final class User
{
}

The ResetPasswordRequest class is a Data Transfer Object (DTO). In your ResetPasswordRequestHandler you should inject the service that is responsible for resetting the password and sending an email.

CustomerNoContact

This could be a Custom (Doctrine ORM) Filter.

Stephan Vierkant
  • 9,674
  • 8
  • 61
  • 97