Reputation: 15555
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}:
GET /api/messages/{name} <- (doesn't work due to conflicting API)
// GET: api/messages/{name}
[HttpGet("{name}")]
public IEnumerable<Message> GetMessagesByName(string name)
{
return _repository.GetMessages().Where(m => m.Owner == name);
}
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
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