kimbaudi
kimbaudi

Reputation: 15555

How to create ASP.NET Core Web API controller method with similar but different parameter

I created a simple Web API with ASP.NET Core. I have the following API:

Now, I want another API to get all messages by message owner's name.

What I tried:

I tried to create this API, but it doesn't work because it conflicts with GET /api/messages/{id}:

Here is my Message model Message.cs:

public class Message
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }
    public string Owner { get; set; }
    public string Text { get; set; }
}

Here is my Messages controller MessagesController.cs:

[Route("api/[controller]")]
public class MessagesController : Controller
{
    private readonly IMessageRepository _repository;

    public MessagesController(IMessageRepository repository)
    {
        _repository = repository;
    }

    // GET: api/messages
    [HttpGet]
    public IEnumerable<Message> Get()
    {
        return _repository.GetMessages();
    }

    // GET api/messages/{id}
    [HttpGet("{id}", Name = "GetMessage")]
    public IActionResult GetById(long id)
    {
        var message = _repository.GetMessage(id);
        if (message == null)
        {
            return NotFound();
        }
        return new ObjectResult(message);
    }

    // POST api/messages
    [HttpPost]
    public IActionResult Post([FromBody]Message message)
    {
        if (message == null)
        {
            return BadRequest();
        }

        _repository.AddMessage(message);

        return CreatedAtRoute("GetMessage", new { id = message.Id }, message);

    }

    // PUT api/messages/{id}
    [HttpPut("{id}")]
    public IActionResult Put(long id, [FromBody]Message message)
    {
        if (message == null || message.Id != id)
        {
            return BadRequest();
        }

        var messageToUpdate = _repository.GetMessage(id);
        if (messageToUpdate == null)
        {
            return NotFound();
        }

        messageToUpdate.Owner = message.Owner;
        messageToUpdate.Text = message.Text;

        _repository.UpdateMessage(messageToUpdate);
        return new NoContentResult();
    }

    // DELETE api/messages/{id}
    [HttpDelete("{id}")]
    public IActionResult Delete(long id)
    {
        var message = _repository.GetMessage(id);
        if (message == null)
        {
            return NotFound();
        }
        _repository.RemoveMessage(id);
        return new NoContentResult();
    }
}

Question:

How can I create an API method to get all messages by message owner's name?

Ideally, I would like the API to look like GET /api/messages/{name}, but don't think its possible since it conflicts with GET /api/messages/{id}.

I'm thinking of creating the API like this, but I'm not sure how.

Solution:

To have GET /api/messages/{name} working without conflicting with GET /api/messages/{id}, change attribute [HttpGet("{id}", Name="GetMessage")] to [HttpGet("{id:long}", Name="GetMessage")] for public IActionResult GetById(long id) method.

To also have GET /api/messages/name/{name} working, add [Route("name/{name}")] attribute to public IEnumerable<Message> GetMessagesByName(string name) method.

Upvotes: 1

Views: 1693

Answers (1)

Michał Jarzyna
Michał Jarzyna

Reputation: 1916

you can put parameter type in route, so your code method should be look like that:

 // GET api/messages/{id}
    [HttpGet("{id:long}", Name = "GetMessage")]
    public IActionResult GetById(long id)
    {
        var message = _repository.GetMessage(id);
        if (message == null)
        {
            return NotFound();
        }
        return new ObjectResult(message);
    }

I think, web api is ignoring parameters types in routes if they are not typed explicitly, so in your example it has two routes like this: api/messages/{object} and when you put explicit type, they are like this: api/messages/{object} and api/messages/{long}

Upvotes: 2

Related Questions