10.4: Getting Message Threads/Conversations

Right now, we can send a request to our API and get the messages a user has sent and another request to retrieve the messages another user has sent to that user.

For displaying a conversation in Angular, it will help if we have a way to display the message conversation or thread between the two users. That's what we'll work on next.

Implementing GetMessageThread() Service Method

In MessageService, implement the GetMessageThread() method:

public async Task<IEnumerable<MessageToReturn>> GetMessageThread(int userId, int recipientId)
{
    var messages = await _context.Messages
                        .Include(u => u.Sender).ThenInclude(p => p.Photos)
                        .Include(u => u.Recipient).ThenInclude(p => p.Photos)
                        .Where(m => (m.RecipientId == userId &&
                                     m.SenderId == recipientId &&
                                     m.RecipientDeleted == false)
                                    ||
                                    (m.RecipientId == recipientId &&
                                     m.SenderId == userId &&
                                     m.SenderDeleted == false))
                        .Select(u => new MessageToReturn
                        {
                            Id = u.Id,
                            SenderId = u.SenderId,
                            SenderKnownAs = u.Sender.KnownAs,
                            SenderPhotoUrl = u.Sender.Photos.FirstOrDefault(p => p.IsMain).Url,
                            RecipientId = u.RecipientId,
                            RecipientKnownAs = u.Recipient.KnownAs,
                            RecipientPhotoUrl = u.Recipient.Photos.FirstOrDefault(p => p.IsMain).Url,
                            Content = u.Content,
                            IsRead = u.IsRead,
                            DateRead = u.DateRead,
                            DateSent = u.DateSent
                        })
                        .OrderByDescending(m => m.DateSent)
                        .ToListAsync();

    return messages;
}

We're running a single query. The only new part is the .Where clause. We're getting both the two Id parameters passed to the method to get all cases where the userId is the recipient as well as the sender and the recipientId is the sender and the recipient. So, basically all messages either user has sent or received from the other user.

Based on whether the userId (which represents our logged in user) is the sender or the receiver - we'll only return messages where either the recipient (our user) hasn't deleted the message or the sender (our user) hasn't deleted the message.

This is a bit tricky to explain. So, try thinking about the code line-by-line until you feel comfortable moving on.

Add GetMessageThread() Controller Method

We'll have to add a new endpoint (thread) to differentiate this endpoint from the GetMessage() endpoint.

[HttpGet("thread/{id}")]
public async Task<IActionResult> GetMessageThread(int userId, int id)
{
    if (userId != int.Parse(User.FindFirst(ClaimTypes.NameIdentifier).Value))
        return Unauthorized();

    var messages = await _messageService.GetMessageThread(userId, id);

    return Ok(messages);
}

Testing in Postman

Before we test the method thread - make sure that you have several messages sent and received between two different users so we have more than just the single message we've been testing so far.

Next, send a GET request to:

http://localhost:5000/api/users/{userId}/messages/thread/{recipientId}

Where userId is the id of the user you have a token for - and the recipientId is the id of the other user you've sent messages to.

You should get a 200 OK response with all messages - both sent and received - between the two users returned in the body:

Last updated