Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow for parameter mapping in path based routing #677

Closed
ahmadnassri opened this issue Nov 2, 2015 · 59 comments
Closed

allow for parameter mapping in path based routing #677

ahmadnassri opened this issue Nov 2, 2015 · 59 comments
Labels
task/feature Requests for new features in Kong

Comments

@ahmadnassri
Copy link
Contributor

ahmadnassri commented Nov 2, 2015

e.g. allow request_path to contain values such as /api/{foo}/bar which map to the upstream_url /upstream/my/api/bar/{foo}

this could also be more globally addressed with regex matching groups e.g.

request_url = '/api/(.+)/bar`
upstream_url = '/upstream/my/api/bar/$1'
@thibaultcha thibaultcha added area/resolver task/feature Requests for new features in Kong labels Nov 2, 2015
@ayush
Copy link

ayush commented Nov 11, 2015

Native support for path parameters in Kong seems like a pretty significant missing piece.

Right off the bat, I want to say that it is clear to me that Kong can proxy to path parameter based APIs. Let us say I have two backend GET APIs /pet/{petId}/get-image and /pet/{petId} If I want Kong to be able to proxy to both, I can simply create an API with request_path as /pet. This will make sure that http://kongserver/pet/123 will be forwarded to http://upstreamserver/pet/123 and http://kongserver/pet/123/get-image will be forwarded to http://upstreamserver/pet/123/get-image (thanks to @travisyates for clarifying this)

However, not having native support for path parameters is problematic. There is probably more to it but I see two resulting side effects of Kong not supporting path parameters:

Kong Blindness

In the above example, Kong is blind to the difference between these two APIs. Even though these are two very different APIS, Kong cannot tell them apart. This leads to problems with using plugins and other features of Kong effectively.

Let us say that Kong did support path parameters and let me define these two APIs separately:

  • Get Image of any pet: /pet/{petId}/get-image
  • Get all details of a /pet/pet/{petId}

In my use case, I want to allow anonymous access to /pet/{petId}/get-image while securing access to /pet/{petId}. Using ACL plugin I would be able to do it but only if Kong allowed me to add these two as different APIs. Right now, Kong cannot tell the difference between these two. And thus I cannot secure these two separately.

Additional complexity of collapsing multiple APIs

As a developer using Kong, I now have to parse all my API definitions and if there are situations like the above /pet/{petId}/get-image and /pet/{petId}, I'll need to deal with the complexity of collapsing them into one API. This kinda sucks. I was working on a project which takes swagger api definitions and puts them in Kong with the right security. This limitation of Kong introduces an impedance mismatch which does not have any ideal solution other than Kong natively supporting path parameters.

@ahmadnassri
Copy link
Contributor Author

while this is a limitation of the functionality, i wouldn't say its a "significant missing piece"

Kong aspires to be a solution for ALL API providers, and the described is just one of many abstractions and methods used. we'll have to balance that equally against other feature requests and with the community's feedback and support we can prioritize appropriately :)

@ayush
Copy link

ayush commented Nov 11, 2015

@ahmadnassri Path parameters are widely used and are even part of open standards like swagger. Completely ignoring them in an API middleware does not seem right. Even Amazon API Gateway has some support for them.

I don't wish to be incessant about how we classify this :) but in the interest of community's feedback and support to help Kong developers prioritize, I'd certainly qualify it as a "significant missing piece".

@ahmadnassri
Copy link
Contributor Author

nobody said anything about "Completely ignoring" them :) just talking about prioritizing features.

there. are. many. feature. requests so we're looking for community feedback for help in prioritization!

@ahmadnassri
Copy link
Contributor Author

related: the official spec: RFC 6570 describing proper URL Templating usage.

@sidharthachatterjee
Copy link

@ahmadnassri Any update on when we can expect this?

@BrianHutchison
Copy link

+1

This would meet a major use-case/need of ours.

@3dbrows
Copy link

3dbrows commented Mar 21, 2016

+1

3 similar comments
@eitanpo
Copy link

eitanpo commented Mar 28, 2016

+1

@RossJayJones
Copy link

+1

@haikuo81
Copy link

+1

@andyfleming
Copy link

Wildcard/parameter mapping would be helpful. In my specific use case I'm looking to do something like:

/something/{alphanumeric}/whatever to be routed to /whatever and I want to add the header x-id: {alphanumeric}

@bradwood
Copy link

bradwood commented Jun 7, 2016

+1

3 similar comments
@matangiz
Copy link

matangiz commented Aug 2, 2016

+1

@lucas-cegatti
Copy link

+1

@vitorsdcs
Copy link

+1

@merlindorin
Copy link

merlindorin commented Aug 24, 2016

+1, really need it, we are stucked now with this missing feature and we have review our mircoservice architecture :'(

The main problem is related to API depth in our services. For example, I can't have different microservice for an endpoint like /users/john/organizations and /users/john/projects. The unique base path that we can handle with kong is /users so... we can have just one service behind (and not one for /users/:username/organizations and /users/:username/projects).

@merlindorin
Copy link

+1 for RFC6570

@kintetsu
Copy link

+1

@dankennedy
Copy link

+1

1 similar comment
@goraniliev
Copy link

+1

@erutherford
Copy link

@ahmadnassri is there any movement on this? We're currently implementing a work around with a nginx proxy in between kong and our services, but this is a less than ideal setup. We'd definitely prefer to have kong handle this path matching on it's own. If you could provide the likelihood or progress on this issue it'd aid us greatly in planning out our future direction.

@thibaultcha
Copy link
Member

This is still on our roadmap but no work has been done as of today yet. Expect such a feature for 0.11 or 0.12, eventually.

@Roam-Cooper
Copy link

Any word on this? Kong is unusable for modern apis without this feature. It's 2016; any petty arguments about this are null and void, in my opinion. Almost every major api in the world uses url parameters.

thibaultcha added a commit that referenced this issue Jul 8, 2017
APIs can now receive user-specified regexes in their `uris` property.
Those regexes will be treated as such by the router.

A URI is considered a regex when its character set does not respect the
reserved list from RFC 3986.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 8, 2017
We now perform efficient matching for URIs based on its property and the
regex being evaluated. We favorise running `ngx.re.find` when the more
expensive `ngx.re.match` is not necessary.

When a regex URI has capture groups, we return them from the router
`exec()` for further processing inside the core, which will be
responsible for passing them along to plugins.

This also has the advantage of being more performant on router cache
hits, since URI stripping is done only once, at matching type, and
cached in the LRU structure. The same way, groups matching is cached as
well.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 11, 2017
APIs can now receive user-specified regexes in their `uris` property.
Those regexes will be treated as such by the router.

A URI is considered a regex when its character set does not respect the
reserved list from RFC 3986.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 11, 2017
We now perform efficient matching for URIs based on its property and the
regex being evaluated. We favorise running `ngx.re.find` when the more
expensive `ngx.re.match` is not necessary.

When a regex URI has capture groups, we return them from the router
`exec()` for further processing inside the core, which will be
responsible for passing them along to plugins.

This also has the advantage of being more performant on router cache
hits, since URI stripping is done only once, at matching type, and
cached in the LRU structure. The same way, groups matching is cached as
well.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 11, 2017
When a value from an API's `uris` property does not respect the reserved
character set from RFC 3986, the router now assumes this value is a
user-specified regex.

User regexes are stored in another index than what we consider "URI
prefixes" (non-regex `uris` values), because while the later needs to be
evaluated based on their length, the same does not apply for the former.
The order in which regexes are specified (and ultimately, APIs are
registered) will be the order in which they will be evaluated.

Because users might specify their own capturing groups once we support
parameters extraction, the URI stripping now uses named capturing
groups. This requires PCRE 7.2+. The original implementation used
numbered capturing groups, but this is not aligned with our long-term
goal of allowing dynamic URI rewriting as part of our Plugins API or
request-transformer plugin.

Breaking changes: requires PCRE 7.2+

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 11, 2017
APIs can now receive user-specified regexes in their `uris` property.
Those regexes will be treated as such by the router.

A URI is considered a regex when its character set does not respect the
reserved list from RFC 3986.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 11, 2017
We now perform efficient matching for URIs based on its property and the
regex being evaluated. We favorise running `ngx.re.find` when the more
expensive `ngx.re.match` is not necessary.

When a regex URI has capture groups, we return them from the router
`exec()` for further processing inside the core, which will be
responsible for passing them along to plugins.

This also has the advantage of being more performant on router cache
hits, since URI stripping is done only once, at matching type, and
cached in the LRU structure. The same way, groups matching is cached as
well.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 17, 2017
When a value from an API's `uris` property does not respect the reserved
character set from RFC 3986, the router now assumes this value is a
user-specified regex.

User regexes are stored in another index than what we consider "URI
prefixes" (non-regex `uris` values), because while the later needs to be
evaluated based on their length, the same does not apply for the former.
The order in which regexes are specified (and ultimately, APIs are
registered) will be the order in which they will be evaluated.

Because users might specify their own capturing groups once we support
parameters extraction, the URI stripping now uses named capturing
groups. This requires PCRE 7.2+. The original implementation used
numbered capturing groups, but this is not aligned with our long-term
goal of allowing dynamic URI rewriting as part of our Plugins API or
request-transformer plugin.

Breaking changes: requires PCRE 7.2+

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 17, 2017
APIs can now receive user-specified regexes in their `uris` property.
Those regexes will be treated as such by the router.

A URI is considered a regex when its character set does not respect the
reserved list from RFC 3986.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 17, 2017
We now perform efficient matching for URIs based on its property and the
regex being evaluated. We favorise running `ngx.re.find` when the more
expensive `ngx.re.match` is not necessary.

When a regex URI has capture groups, we return them from the router
`exec()` for further processing inside the core, which will be
responsible for passing them along to plugins.

This also has the advantage of being more performant on router cache
hits, since URI stripping is done only once, at matching type, and
cached in the LRU structure. The same way, groups matching is cached as
well.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 20, 2017
When a value from an API's `uris` property does not respect the reserved
character set from RFC 3986, the router now assumes this value is a
user-specified regex.

User regexes are stored in another index than what we consider "URI
prefixes" (non-regex `uris` values), because while the later needs to be
evaluated based on their length, the same does not apply for the former.
The order in which regexes are specified (and ultimately, APIs are
registered) will be the order in which they will be evaluated.

Because users might specify their own capturing groups once we support
parameters extraction, the URI stripping now uses named capturing
groups. This requires PCRE 7.2+. The original implementation used
numbered capturing groups, but this is not aligned with our long-term
goal of allowing dynamic URI rewriting as part of our Plugins API or
request-transformer plugin.

Breaking changes: requires PCRE 7.2+

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 20, 2017
APIs can now receive user-specified regexes in their `uris` property.
Those regexes will be treated as such by the router.

A URI is considered a regex when its character set does not respect the
reserved list from RFC 3986.

Implements: #677 (partially)
thibaultcha added a commit that referenced this issue Jul 20, 2017
We now perform efficient matching for URIs based on its property and the
regex being evaluated. We favorise running `ngx.re.find` when the more
expensive `ngx.re.match` is not necessary.

When a regex URI has capture groups, we return them from the router
`exec()` for further processing inside the core, which will be
responsible for passing them along to plugins.

This also has the advantage of being more performant on router cache
hits, since URI stripping is done only once, at matching type, and
cached in the LRU structure. The same way, groups matching is cached as
well.

Implements: #677 (partially)
@rdzak
Copy link

rdzak commented Jul 20, 2017

Hi @thibaultcha!

First of all - thank so much for working on it. Do I understand correctly that this feature allows dynamically building upstream URLs from available data such as consumer_ids? For instance, when using auth plugin, consumer_id is sent currently in the header to upstream API. Will this allow me to dynamically build upstream routes using this variable like that: /customers/{consumer_id}/something?
Also I'm super curious when is the next release planned :)

Kind regards.

@thibaultcha
Copy link
Member

thibaultcha commented Jul 20, 2017

@rdzak Hi,

Do I understand correctly that this feature allows dynamically building upstream URLs from available data such as consumer_ids?

It does not. This work enabled URIs regexp matching and capturing groups extraction. It then exposes the captured groups to the plugins for the lifecycle of the request. It is now up to the plugin to be updated and to use those capturing groups to do something. That is beyond the scope of the proposed PR, and still in the scope of this issue. We are working on it.

Additionally, if the value you want to use comes from the request headers, then it is not dependent on the regexp PR in any way, but entirely on the request-transformer plugin.

Also I'm super curious when is the next release planned :)

We have an RC 2 coming up next week, and stable 0.11 in the upcoming weeks if RC 2 is successful.

@thibaultcha
Copy link
Member

thibaultcha commented Aug 21, 2017

Hi everyone!

As of today, all the work that we planned for this so far has been released in 0.11.0. So, before closing the conversation here, I would like to recap a few things.

This issue actually described two features:

  1. The ability to set regexes in an API's uris attribute (and match an API with not only prefixes of URIs, but also dynamic path segments).
  2. Extracting the dynamic path segments (whether named regex capturing groups or not), and substitute them in the upstream call URI.

As of today, 1. is available starting from Kong 0.11.0 🎉, and 2. is available as part of our Mashape Enterprise subscription. In our most recent release for our Enterprise customers, we've improved the request-transformer plugin to support substitution for Lua land values, such as: config.uri.replace=/users/$(uri_captures.user_id)/profile.

You can find more information about our Mashape Enterprise subscription and its additional features on top of Kong at: https://mashape.com/enterprise.

As a "bonus feature", I would like to highlight that Kong 0.11.0 also includes:

  1. Consumption of the API router matches from the plugins via the new ngx.ctx.router_matches variable.

This should allow for some good hacking sessions in your Kong custom plugins 😉

With that said, I believe we can now close this conversation and consider it implemented under the scope provided by this issue! You can checkout Kong 0.11.0 here: https://github.com/Mashape/kong/releases/tag/0.11.0

Thanks!

@merlindorin
Copy link

At least, we don't forget that kong is also an entreprise product 🤔

Thx for the work, this feature really change the game for us. For the first time we can purpose your product to our customer because it fits our development. 💌

I hope that the next big step will be an integration of Swagger (at least params/body/query sync validation) 👍

@mrproper
Copy link

mrproper commented Sep 8, 2017

What is the correct way to do a regex in a uris attribute, when i do it via curl it does not yield the results im after:
curl http://127.0.0.1:8001/apis/foo -X PATCH --data 'uris=/v1/foo/\d+/bar' curl http://127.0.0.1:8001/apis/foo -X GET { ... "uris" : [ "/v1/foo/\\d /bar" ], ... }

@RolphH
Copy link

RolphH commented Sep 8, 2017

@mrproper see #2681 (comment)

@techtyler
Copy link

techtyler commented Oct 3, 2017

Is it possible to use this feature with QueryString parameters? I'm having issue with getting the regex to match the "?" character in the request uri. I want to set up 2 apis with the only difference being the presence of the query string (such as "?debug=true") is added.

Example (get user by ID with debug querystring)
RequestURI: /User/[0-9]{8}\?debug=true

I've attempted to escape and double escape the '?' but it seems to be ignored. If I use another character such as '&', everything works fine. There seems to be some issue with the reserved regex characters. I've also tried using the url encoded "%3F" but that doesn't get sent properly to my service and it does not pick up the query string parameters.

@thibaultcha
Copy link
Member

@techtyler Copying here my answer to you from Gitter for future reference to this thread (please avoid cross-posintg in the future):

@techtyler Kong’s router evaluates URIs after stripping out the request arguments from the request line, which is why this regex will never match an incoming URI
@techtyler No plugin or core feature would allow you to route based on querystring args quite yet. You’d have to develop some in house solution in a plugin

Also, I will now be locking this issue to avoid further noise. The usual support channels (Gitter/Freenode/Mailing list) are the preferred channel of communication for getting help and asking questions. Today, GitHub issues are only looked at when actually reporting bugs. Thank you for your cooperation!

@Kong Kong locked and limited conversation to collaborators Oct 3, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
task/feature Requests for new features in Kong
Projects
None yet
Development

No branches or pull requests