Skip to content
Snippets Groups Projects
Commit 00b140c1 authored by Václav Bílý's avatar Václav Bílý :cowboy:
Browse files

WebApi - PostEndpoints using mediatR

parent 6993472c
No related branches found
No related tags found
No related merge requests found
using ErrorOr;
using MediatR;
using SocialNetwork.Social.Application.Common.Interfaces;
using SocialNetwork.Social.Domain.Entities.Feed;
namespace SocialNetwork.Social.Application.Posts.Commands;
public record CommentPostCommand(Guid PostId, Guid CommenterId, string Content) : IRequest<ErrorOr<Comment>>;
public class CommentPostCommandHandler(IApplicationDbContext dbContext) : IRequestHandler<CommentPostCommand, ErrorOr<Comment>>
{
public async Task<ErrorOr<Comment>> Handle(CommentPostCommand request, CancellationToken cancellationToken)
{
var postId = request.PostId;
var post = await dbContext.Posts.FindAsync([postId], cancellationToken: cancellationToken);
if (post is null) return PostErrors.PostNotFound(postId);
var comment = new Comment {AuthorId = request.CommenterId, Content = request.Content, PostId = request.PostId,};
await dbContext.Comments.AddAsync(comment, cancellationToken);
post.Comments.Add(comment);
await dbContext.SaveChangesAsync(cancellationToken);
dbContext.Posts.Update(post);
await dbContext.SaveChangesAsync(cancellationToken);
return comment;
}
}
public class CommentPostCommandValidator : AbstractValidator<CommentPostCommand>
{
public CommentPostCommandValidator()
{
RuleFor(p => p.PostId)
.NotEmpty();
RuleFor(p => p.CommenterId)
.NotEmpty();
RuleFor(p => p.Content)
.NotEmpty()
.Length(3, 512);
}
}
using ErrorOr;
using MediatR;
using SocialNetwork.Social.Application.Common.Interfaces;
using SocialNetwork.Social.Domain.Entities.Feed;
namespace SocialNetwork.Social.Application.Posts.Commands;
public record PublishPostCommand(Guid AuthorId, string Title, string Content) : IRequest<ErrorOr<Post>>;
public class PublishPostCommandHandler(IApplicationDbContext dbContext) : IRequestHandler<PublishPostCommand, ErrorOr<Post>>
{
public async Task<ErrorOr<Post>> Handle(PublishPostCommand request, CancellationToken cancellationToken)
{
var post = new Post {AuthorId = request.AuthorId, Title = request.Title, Content = request.Content};
await dbContext.Posts.AddAsync(post, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
// TODO fire event PostPublished
return post;
}
}
public class PublishPostCommandValidator : AbstractValidator<PublishPostCommand>
{
public PublishPostCommandValidator()
{
RuleFor(p => p.AuthorId)
.NotEmpty();
RuleFor(p => p.Title)
.NotEmpty()
.Length(3, 64);
RuleFor(p => p.Content)
.NotEmpty()
.Length(3, 512);
}
}
......@@ -16,7 +16,7 @@ public class GetPostByIdCommandHandler(IApplicationDbContext dbContext) : IReque
.Posts
.FindAsync(new object?[] {postIdToFind}, cancellationToken: cancellationToken);
if (post is null) return Error.NotFound("PostNotFound", $"Post with id: {postIdToFind} not found");
if (post is null) return PostErrors.PostNotFound(postIdToFind);
return post;
}
......
using ErrorOr;
using MediatR;
using SocialNetwork.Social.Application.Common.Interfaces;
namespace SocialNetwork.Social.Application.Posts.Commands;
public record LikePostCommand(Guid PostId, Guid LikerId) : IRequest<ErrorOr<Success>>;
public class LikePostCommandHandler(IApplicationDbContext dbContext) : IRequestHandler<LikePostCommand, ErrorOr<Success>>
{
public async Task<ErrorOr<Success>> Handle(LikePostCommand request, CancellationToken cancellationToken)
{
var requestPostId = request.PostId;
var post = await dbContext.Posts.FindAsync(requestPostId);
if (post is null) return PostErrors.PostNotFound(requestPostId);
post.LikesCount++; // I would create a whole table for likers and postId to add who liked the post
// TODO fire post liked event
await dbContext.SaveChangesAsync(cancellationToken);
return Result.Success;
}
}
using ErrorOr;
namespace SocialNetwork.Social.Application.Posts;
public static class PostErrors
{
public static Error PostNotFound(Guid postId) =>
Error.NotFound("PostNotFound", $"Post with id: {postId} not found");
}
using ErrorOr;
using MediatR;
using Microsoft.EntityFrameworkCore;
using SocialNetwork.Social.Application.Common.Interfaces;
using SocialNetwork.Social.Application.Posts.Commands;
using SocialNetwork.Social.Domain.Entities.Feed;
namespace WebApi.Endpoints;
......@@ -27,55 +24,56 @@ public class PostEndpoints
private async Task<IResult> GetPostById(Guid postId, ISender sender)
{
var post = await sender.Send(new GetPostByIdCommand(postId));
return post.MatchFirst(
var errorOrPost = await sender.Send(new GetPostByIdCommand(postId));
return errorOrPost.MatchFirst(
Results.Ok,
error => error.Type switch
{
ErrorType.NotFound => Results.NotFound(error.Code),
_ => Results.BadRequest(error.Code)
ErrorType.NotFound => Results.NotFound(error.Description),
_ => Results.BadRequest(error.Description)
}
);
}
private async Task<IResult> CommentPost(Guid postId, Comment comment, IApplicationDbContext dbContext)
private async Task<IResult> CreatePost(PublishPostCommand command, ISender sender)
{
var post = await dbContext.Posts.FindAsync(postId);
if (post is null) return Results.NotFound("Post not found");
if (post.Comments.Any(c => c.Id == comment.Id)) return Results.Conflict("Comment already exists");
comment.PostId = postId;
await dbContext.Comments.AddAsync(comment);
post.Comments.Add(comment);
await dbContext.SaveChangesAsync();
dbContext.Posts.Update(post);
await dbContext.SaveChangesAsync();
return Results.Created($"api/posts/{postId}", comment);
var errorOrCreatedPost = await sender.Send(command);
return errorOrCreatedPost.MatchFirst(
createdPost => Results.Created($"/api/posts/{createdPost.Id}", createdPost),
error => error.Type switch
{
ErrorType.Validation => Results.BadRequest(error.Description),
ErrorType.Failure => Results.Problem(error.Description),
_ => Results.BadRequest(error.Description)
}
);
}
private async Task<IResult> CreatePost(Post post, IApplicationDbContext dbContext)
private async Task<IResult> CommentPost(Guid postId, CommentPostCommand command, ISender sender)
{
var doesPostExist = await dbContext.Posts.AnyAsync(p => p.Id == post.Id);
if (doesPostExist) return Results.Conflict();
var entry = dbContext.Posts.Add(post);
await dbContext.SaveChangesAsync();
var persistedPost = entry.Entity;
return Results.Created($"/api/posts/{persistedPost.Id}", persistedPost);
var errorOrComment = await sender.Send(command with {PostId = postId});
return errorOrComment.MatchFirst(
comment => Results.Created($"api/posts/{postId}", comment),
error => error.Type switch
{
ErrorType.Validation => Results.BadRequest(error.Description),
ErrorType.NotFound => Results.NotFound(error.Description),
_ => Results.BadRequest(error.Description)
}
);
}
private async Task<IResult> LikePost(Guid postId, Guid likerId, IApplicationDbContext dbContext)
private async Task<IResult> LikePost(Guid postId, LikePostCommand command, ISender sender)
{
var post = await dbContext.Posts.FindAsync(postId);
if (post is null) return Results.NotFound();
post.LikesCount++;
// TODO add who liked the post
await dbContext.SaveChangesAsync();
return Results.Ok();
var errorOrSuccess = await sender.Send(command with {PostId = postId});
return errorOrSuccess.MatchFirst(
_ => Results.Ok(),
error => error.Type switch
{
ErrorType.Validation => Results.BadRequest(error.Description),
ErrorType.NotFound => Results.NotFound(error.Description),
_ => Results.BadRequest(error.Description)
}
);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment