Search code examples
.net-coremicroservicesurl-routingservice-discoveryocelot

Path conflict in Ocelot routing configuration


How would you set re-reoute following two set of similar routes to different machines. Please advise.

Problem/Question: The conflicting situation is between /customers/1 & /customers/1/products where each one is going to a different machine.

- machine name: customer

GET /customers
GET /customers/1
POST /customers
PUT /customers1
DELETE /customers/1

- machine name: customerproduct

GET /customers/1/products
PUT /customers/1/products

ocelot.json

 {
  "ReRoutes": [

    {  
      "DownstreamPathTemplate": "/customers/{id}", 
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "customer",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/customers/{id}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ]
    },

    {
      "DownstreamPathTemplate": "/customers/{id}/products",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "customerproduct",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/customers/{id}/products",
      "UpstreamHttpMethod": [ "Get", "Put" ]
    }

  ],

  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:80"
  }

}

Solution

  • Just adding an answer based on the OP's own solution in the comments.

    The reason this was not working is because of order of evaluation. Ocelot will evaluate paths in the order they are specified, unless the priority property is specified on the routes (see docs https://ocelot.readthedocs.io/en/latest/features/routing.html#priority)

    So the in the following routing config:

    {
       "ReRoutes":[
          {
             "UpstreamPathTemplate":"/customers/{id}", // <-- will be evaluated first
             ...
          },
          {
             "UpstreamPathTemplate":"/customers/{id}/products",
             ...
          },
          ...
       ],
       ...
    }
    

    the first path will be evaluated and Ocelot will match to this path even if the upstream call specifies the /products sub-path.

    To fix this, either change the ordering so that the more specific path is evaluated first:

    {
       "ReRoutes":[
          {
             "UpstreamPathTemplate":"/customers/{id}/products", // <-- will be evaluated first
             ...
          },
          {
             "UpstreamPathTemplate":"/customers/{id}",
             ...
          },
          ...
       ],
       ...
    }
    

    or use the priority property, with the priority being used to indicate the desired order of evaluation:

    {
       "ReRoutes":[
          {
             "UpstreamPathTemplate":"/customers/{id}",
             "Priority": 0, 
             ...
          },
          {
             "UpstreamPathTemplate":"/customers/{id}/products", // <-- will be evaluated first
             "Priority": 1, 
             ...
          },
          ...
       ],
       ...
    }