skip to Main Content

Let’s say I want to implement a User API Controller. Client needs to get users by integer ID, so I create a method GET - /api/User/{id:int}.

Then for some reason I want to implement getting a user by its name. The most obvious solution is to create GET - /api/User/{name:string} but this method will be conflicting with the previous one. Naming a method /api/UserByName/{name:string} breaks REST entity rules.

How can I deal with this problem without breaking REST rules?

upd: I just wrote the following code to create multiple routes:

    [HttpGet]
    public async Task<IActionResult> Get([FromQuery] int id)
    {
        return Ok();
    }
    
    [HttpGet]
    public async Task<IActionResult> Get([FromQuery] string name)
    {
        return Ok();
    }

This code cannot be translated by swagger and produces an error
Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Conflicting method/path combination "GET WeatherForecast" for actions - WebApiSkeleton.API.Contro llers.WeatherForecastController.Get (WebApiSkeleton.API),WebApiSkeleton.API.Controllers.WeatherForecastController.Get (WebApiSkeleton.API). Actions require a unique method/path combination for Swagger/OpenAPI 3.0. Use ConflictingActionsResolver as a workaround

Calling a method raises another exception:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: WebApiSkeleton.API.Controllers.WeatherForecastController.Get (WebApiSkeleton.API) WebApiSkeleton.API.Controllers.WeatherForecastController.Get (WebApiSkeleton.API)

2

Answers


  1. ASP.Net core routing uses a precedence in selecting routes, usually from more specific to generic. Hence, if you have two routes one with {id:int} and the other one without any qualifier or :alpha qualifier, then if you send an int you the {id:int} will be hit otherwise, the other more generic route will be hit. This means that these two routes can co-exist and will do what you want to do:

    [HttpGet("something/{id:int}")]
    public IActionResult Get1(int id)
    {
        return Ok();
    }
    
    [HttpGet("something/{id}")]
    public IActionResult Get2(string id)
    {
        return Ok();
    }
    

    You can test to call these two enpoints using postman or any http client.
    The error you are having is probably related to swagger not able to generate documentation, which says something like this :
    Conflicting method/path combination
    That has nothing to do with asp.net core but swagger.

    What you can do is ignore the one that takes {id:int} from swagger, since it’s the less generic. You can use : [ApiExplorerSettings(IgnoreApi = true)] for that.
    Once you do that, if you open swagger you will see a single endpoint but if you try it out with an int you will hit the {id:int} endpoint, otherwise you will hit the {id} endpoint.

    Login or Signup to reply.
  2. What I did mean by using [FromQuery] is this.
    It would required for you to have a class with id and name

    public class UserFilter
    {
        public int? Id { get; set; }
        public string Name { get; set; }
    }
    

    Then have the route like this

    [HttpGet]
    public async Task<IActionResult> Get([FromQuery] UserFilter filter)
    {
        if (filter.Id.HasValue)
        {
            // Search by id
        }
        else if (!string.IsNullOrWhiteSpace(filter.Name))
        {
            // Searh by name
        }
        return Ok();
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search