This question concerns CQRS and DDD.
I want to create a post comment. This is my endpoint: /posts/{postId}/comments <-- Http POST
But firstly I need to check if a post with a specific ID exists. In each article, each book about CQRS and DDD each class name of query starts with Getxxxxx and it returns data. I didn't find anywhere an example of query which checks if an item exists and returns true/false, why?? I wonder if I can create a query called "PostExistsQuery". Because on the whole internet there is no similar example. :O Maybe I am doing something wrong? :0
[HttpPost("/posts/{postId}/comments")]
public async Task<IActionResult> CreatePostComment(Guid postId, CreateCommentDTO commentDTO)
{
if (await _mediator.Send(new PostExistsQuery(postId)) == false) // check if a post exists
{
return NotFound();
}
var commentCommand = new CreateCommentCommand(Guid.NewGuid(), postId, commentDTO.Author, commentDTO.Content);
await _mediator.Send(commentCommand);
return CreatedAtAction(nameof(GetCommentById), new { id = commentCommand.CommentId });
}
CodePudding user response:
You're leaking business logic into the API layer. The API layer (controller) should simply prepare a command and send it to the command handler, perhaps applying access control beforehand if required.
Depending on your domain model, one of the following would happen:
the command handler tries to retrieve the post from the repository in order to call AddComment on it. If post is null at this point then throw.
you get a post from the repository and pass that into the comment factory, which will throw if null.
you simply pass in the Id and validate its existence using a domain event handler. If it does not exist, throw.
your database provider will throw an FK violation when it tries to add a comment with an invalid post id.
Whichever it may be, you can capture in your command handler (or command handling pipeline) and throw a PostNotFoundException back to the API, which can then return that in a BadRequest.
CodePudding user response:
Try to read more about Layers in DDD, especially about Domain and Application Layers. I think you missed some core concepts, because your example shows you trying to implement business login in your API.
In your concrete example Domain layer is responsible for checking that your aggregate exists. You should use Repository pattern (or similar) in your command handler to fetch your aggregates and save them after processing. When aggregate not found, Repository throws an Exception.
P.S. CQRS pattern is all about responsibility segregation of read and write sides of your application, so you should not use read-model in command side.