Home > database >  Routing: Solve ambigous requests with query parameters
Routing: Solve ambigous requests with query parameters

Time:03-01

Given the RecordsController below, the following requests shall be possible and mapped to the endpoints accordingly

  1. /api/Records
  2. /api/Records/9b858599-7639-45da-acd6-a1323fb019b5
  3. /api/Records/9b858599-7639-45da-acd6-a1323fb019b5?asOf=2022-01-01
  4. /api/Records/9b858599-7639-45da-acd6-a1323fb019b5?From=2022-01-01&To=2022-03-01

Mapped to:

  1. GetAll(Guid id)
  2. Get(Guid id)
  3. GetAsOf(Guid id1, [FromQuery] string asOf)
  4. GetHistory(Guid id2, [FromQuery] string from, [FromQuery] string to)
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication1.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class RecordsController : ControllerBase
    {
        private readonly ILogger<RecordsController> _logger;

        public RecordsController(ILogger<RecordsController> logger)
        {
            _logger = logger;
        }

        [HttpGet()]
        public ActionResult<IEnumerable<Record>> GetAll()
        {
            _logger.LogInformation("GetAll() was used");
            return Ok();
        }

        [HttpGet("{id:Guid}")]
        public ActionResult<Record> Get(Guid id)
        {
            _logger.LogInformation("Get() was used");
            return Ok();
        }

        [HttpGet("{id1:Guid}")]
        public ActionResult<IEnumerable<Record>> GetAsOf(Guid id1, [FromQuery] string asOf)
        {
            _logger.LogInformation("GetAsOf() was used");
            return Ok();
        }
        [HttpGet("{id2:Guid}")]
        public ActionResult<IEnumerable<Record>> GetHistory(Guid id2, [FromQuery] string from, [FromQuery] string to)
        {
            _logger.LogInformation("GetHistory() was used");
            return Ok();
        }
    }

    public class Record
    {
        public Guid Id { get; set; }
        public string Comment { get; set; } = string.Empty;
    }
}

This is not working as expected. An implementation as above leads to a AmbiguousMatchException.

Using the IRouteTemplateProvider.Order there is a possibility to influence this behavior but then the requests 2. - 4. are routed to the endpoint with the lowest Order.

Do you see any possibities apart from changing FromQuery to FromRoute?

Thanks!

CodePudding user response:

Methods 2-4 are indeed ambiguous as they all are the same endpoint, just with different query parameters. So you either need to make them have different routes, or you can express the endpoint as a single method with all the possible query parameters and from there, use which query parameters are present to map to the specific methods.

HttpGet("{id:Guid}")]
public ActionResult<Record> Get(Guid id, [FromQuery] string asOf, [FromQuery] string from, [FromQuery] string to)
{
    if (asOf != null) return GetAsOf(id, asOf);
    if (from != null && to != null) return GetHistory(id, from, to);
    return Get(id);
}

public ActionResult<Record> Get(Guid id)
{
    _logger.LogInformation("Get() was used");
    return Ok();
}

public ActionResult<IEnumerable<Record>> GetAsOf(Guid id, string asOf)
{
    _logger.LogInformation("GetAsOf() was used");
    return Ok();
}

public ActionResult<IEnumerable<Record>> GetHistory(Guid id2, [FromQuery] string from, [FromQuery] string to)
{
    _logger.LogInformation("GetHistory() was used");
    return Ok();
}
  • Related