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

Routes entity page, router expressions, proxying #168

Merged
merged 38 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2d0e1ab
Start revising routes entity page
cloudjumpercat Dec 10, 2024
2804553
Continue revising routes entity, start drafting the rewrite URLs how to
cloudjumpercat Dec 10, 2024
9a845e9
Fix vale spelling error
cloudjumpercat Dec 11, 2024
117daae
Capitalize entities
cloudjumpercat Dec 11, 2024
c3c8da6
Revise how to after testing
cloudjumpercat Dec 11, 2024
ccbd48e
Plan out routing section for matching and priority section split
cloudjumpercat Dec 11, 2024
e9b3935
Apply suggestions from code review
cloudjumpercat Dec 12, 2024
5a74da6
Edit routes, upstream, add proxy page, update source file with doc links
cloudjumpercat Dec 12, 2024
2bd7119
Merge branch 'main' into routes-entity
cloudjumpercat Dec 13, 2024
89adbb6
Fix broken breadcrumb link
cloudjumpercat Dec 13, 2024
45b8d04
Revise a whole bunch of pages
cloudjumpercat Dec 13, 2024
5cf9492
Revise proxy reference and routing
cloudjumpercat Dec 16, 2024
6c175ce
Start adding the needed expressions router pages
cloudjumpercat Dec 16, 2024
3aefeb7
Add drafts of all expressions docs
cloudjumpercat Dec 17, 2024
3336680
Finish expressions router concept page
cloudjumpercat Dec 18, 2024
1f69366
Remove expressions router how to and move enabling info to other pages
cloudjumpercat Dec 18, 2024
7165bbc
Apply suggestions from code review
cloudjumpercat Dec 18, 2024
81e2355
Apply Angel's remaining feedback to the rewrite urls how to
cloudjumpercat Dec 18, 2024
34e2faa
Apply suggestions from code review
cloudjumpercat Dec 18, 2024
586509d
Apply Lena's feedback to Upstream entity page
cloudjumpercat Dec 18, 2024
e819205
Revise Routes entity based on feedback
cloudjumpercat Dec 18, 2024
1a1733d
Revise proxy reference
cloudjumpercat Dec 19, 2024
990afc6
Minor link fixes, make vale happy again
cloudjumpercat Dec 19, 2024
fc92c6f
Fix broken links
cloudjumpercat Dec 19, 2024
c5eb4b1
Remove upstream and target entity pages since they are now handled in…
cloudjumpercat Dec 19, 2024
318b8d6
Convert expressions router image to mermaid
cloudjumpercat Dec 19, 2024
4300032
Merge branch 'main' into routes-entity
cloudjumpercat Dec 19, 2024
1def049
Apply remaining feedback
cloudjumpercat Dec 19, 2024
5d27dfe
Add proxying ref placeholder page with todo
cloudjumpercat Jan 6, 2025
6adb293
Merge branch 'main' into routes-entity
lena-larionova Jan 8, 2025
3d090cf
Apply suggestions from code review
cloudjumpercat Jan 10, 2025
847bb93
Apply remaining feedback
cloudjumpercat Jan 10, 2025
5f9074c
Merge branch 'main' into routes-entity
cloudjumpercat Jan 10, 2025
e0b7bc2
Apply new feature table formatting
cloudjumpercat Jan 10, 2025
d03b20d
Fix feature table formatting
cloudjumpercat Jan 10, 2025
e6e72cf
Apply suggestions from code review
lena-larionova Jan 10, 2025
446ab46
fix centering issue in feature tables
lena-larionova Jan 10, 2025
d9cc8f6
fix faqs key
lena-larionova Jan 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 142 additions & 28 deletions app/_gateway_entities/route.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,171 @@ content_type: reference
entities:
- route

description: A route is a path to a resource within an upstream application.
description: A Route is a path to a resource within an upstream application.
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

related_resources:
- text: Services
- text: Gateway Services
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved
url: /gateway/entities/service/
- text: Routing in {{site.base_gateway}}
url: /gateway/routing/
- text: Expressions router
url: /gateway/routing/expressions/
- text: Upstream entity
url: /gateway/entities/upstream/
- text: Proxying with {{site.base_gateway}}
url: /gateway/traffic-control/proxy/

tools:
- admin-api
- konnect-api
- kic
- deck
- terraform
- admin-api
- konnect-api
- kic
- deck
- terraform

schema:
api: gateway/admin-ee
path: /schemas/Route
api: gateway/admin-ee
path: /schemas/Route

---

## What is a route?
## What is a Route?

{{page.description}} Services can store collections of objects like plugin configurations, and policies, and they can be associated with routes. In {{site.base_gateway}}, routes typically map to endpoints that are exposed through the {{site.base_gateway}} application. Routes can also define rules that match requests to associated services. Because of this, one route can reference multiple endpoints. A basic route should have a name, path or paths, and reference an existing service.
{{page.description}} [Gateway Services](/gateway/entities/service/) can store collections of objects like plugin configurations and policies, and they can be associated with Routes. In {{site.base_gateway}}, Routes typically map to endpoints that are exposed through the {{site.base_gateway}} application. Routes determine how (and if) requests are sent to their Services after they reach {{site.base_gateway}}. Where a Service represents the backend API, a Route defines what is exposed to clients.
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

You can also configure routes with:
Routes can also define rules that match requests to associated Services. Because of this, one Route can reference multiple endpoints. Once a Route is matched, {{site.base_gateway}} proxies the request to its associated Service. A basic Route should have a name, path or paths, and reference an existing Service.

* Protocols: The protocol used to communicate with the upstream application.
* Hosts: Lists of domains that match a route
* Methods: HTTP methods that match a route
* Headers: Lists of values that are expected in the header of a request
* Redirect status codes: HTTPS status codes
* Tags: Optional set of strings to group routes with
Use Routes if you don't need to load balance traffic to hosts. If you need to do load balancing between hostnames, configure your hosts in an [Upstream](/gateway/entities/upstream/) instead.

## Route and service interaction
## Route and Service interaction

Routes, in conjunction with [services](/gateway/entities/service/), let you expose your services to applications with {{site.base_gateway}}. {{site.base_gateway}} abstracts the service from the applications by using routes. Since the application always uses the route to make a request, changes to the services, like versioning, don’t impact how applications make the request. Routes also allow the same service to be used by multiple applications and apply different policies based on the route used.
Routes, in conjunction with [Services](/gateway/entities/service/), let you expose your Services to applications with {{site.base_gateway}}. {{site.base_gateway}} abstracts the Service from the applications by using Routes. Since the application always uses the Route to make a request, changes to the Services, like versioning, don’t impact how applications make the request.

For example, if you have an external application and an internal application that need to access the `example_service` service, but the external application should be limited in how often it can query the service to assure no denial of service. If a rate limit policy is configured for the service when the internal application calls the service, the internal application is limited as well. Routes can solve this problem.
The following diagram shows how Routes interact with other {{site.base_gateway}} entities:

In the example above, two routes can be created, say /external and /internal, and both routes can point to `example_service`. A policy can be configured to limit how often the /external route is used and the route can be communicated to the external client for use. When the external client tries to access the service via {{site.base_gateway}} using /external, they are rate limited. But when the internal client accesses the service using {{site.base_gateway}} using /internal, the internal client will not be limited.
{% mermaid %}
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved
flowchart LR
A(External application)
B("`Route (/external)`")
C("`Service (example-service)`")
D(Upstream application)
E(Internal application)
F("`Route (/internal)`")

subgraph id1 ["`
**KONG GATEWAY**`"]
B <--requests
responses--> C
F <--requests
responses--> C
end

## Dynamically rewrite request URLs with routes
A <--requests
responses--> B
E <--requests
responses--> F

Routes can be configured dynamically to rewrite the requested URL to a different URL for the upstream. For example, your legacy upstream endpoint may have a base URI like `/api/old/`. However, you want your publicly accessible API endpoint to now be named `/new/api`. To route the service's upstream endpoint to the new URL, you could set up a service with the path `/api/old/` and a route with the path `/new/api`.
C <--requests
responses--> D

{{site.base_gateway}} can also handle more complex URL rewriting cases by using regular expression capture groups in the route path and the [Request Transformer Advanced](https://docs.konghq.com/hub/kong-inc/request-transformer-advanced/) plugin. For example, this can be used when you must replace `/api/<function>/old` with `/new/api/<function>`.
B -.->|Rate Limiting plugin| C

{{site.base_gateway}} 3.0.x or later ships with a new router. The new router can use regex expression capture groups to describe routes using a domain-specific language called Expressions. Expressions can describe routes or paths as patterns using regular expressions. For more information about how to configure the router using Expressions, see [How to configure routes using expressions](https://docs.konghq.com/gateway/latest/key-concepts/routes/expressions/).
style id1 rx:10,ry:10

{% endmermaid %}

Routes also allow the same Service to be used by multiple applications and apply different policies based on the Route used.
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

For example, say you have an external application and an internal application that need to access the `example_service` Service, but the *external* application should be limited in how often it can query the Service to avoid a denial of service. If you apply a rate limit policy to the Service and the *internal* application calls it, the internal application is also limited. Routes can solve this problem.


In this example, you can create two Routes to handle the two applications, say `/external` and `/internal`, and point both of them to `example_service`.
You can configure a policy to limit how often the `/external` Route is used.
When the external application tries to access the Service via {{site.base_gateway}} using `/external`, it's rate limited.
But when the internal application accesses the Service using {{site.base_gateway}} using `/internal`, the internal application isn't limited.

## Route use cases

Use the following table to help you understand how Routes can be configured for different use cases:
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

| You want to... | Then use... |
lena-larionova marked this conversation as resolved.
Show resolved Hide resolved
|--------|----------|
| Rate limit internal and external traffic to a Service | [Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) |
| Perform a simple URL rewrite, such as renaming your legacy `/api/old/` Upstream endpoint to a publicly accessible API endpoint that is now named `/new/api`. | [Set up a Gateway Service with the old path and a Route with new path](/how-to/rewrite-simple-request-urls-with-routes/) |
| Perform a complex URL rewrite, such as replacing `/api/<function>/old` with `/new/api/<function>`. | [Request Transformer Advanced plugin](/plugins/request-transformer-advanced/) |
| Describe Routes or paths as patterns using regular expressions. | [Expressions router](/gateway/routing/expressions/) |
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

## How routing works

For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. {{site.base_gateway}} handles routing in the following order:

1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request.

If the rule count for the given request is the same in two Routes `A` and
`B`, then the following tiebreaker rules will be applied in the order they
are listed. Route `A` will be selected over `B` if:
* `A` has only "plain" Host headers and `B` has one or more "wildcard"
host headers
* `A` has more non-Host headers than `B`.
* `A` has at least one "regex" paths and `B` has only "plain" paths.
* `A`'s longest path is longer than `B`'s longest path.
* `A.created_at < B.created_at`
1. If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request.
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved
1. As soon as a Route yields a match, the router stops matching and {{site.base_gateway}} uses the matched Route to [proxy the current request](/gateway/traffic-control/proxy/).

{{site.base_gateway}} uses a router to route requests. There are two different routers you can use. Which you should use depends on your use case and {{site.base_gateway}} version:
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

| Recommended {{site.base_gateway}} version | Routing method | Description |
|-------------------------------|----------------|-------------|
| 2.9.x or earlier | Traditional compatibility | Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The default routing method for {{site.base_gateway}}. Doesn't handle complex routing logic. |
| 3.0.x or later | [Expressions router](/gateway/routing/expressions/) | The recommended method for anyone running {{site.base_gateway}} 3.0.x or later. Can be run in both `traditional_compat` and `expressions` modes. Handles complex routing logic and regex in Routes. |

### Path matching

When proxying with path prefixes, the longest paths get evaluated first. This allows you to define two Routes with two paths: `/service` and `/service/resource`, and ensure that the former doesn't “shadow” the latter.

Keep the following path matching recommendations in mind when configuring paths:
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

* **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`. For example: `paths: ["~/foo/bar$"]`. Routers with a large number of regexes can consume traffic intended for other rules. Regular expressions are much more expensive to build and execute and can’t be optimized easily. You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/).
* **Capturing groups:** Capturing groups are also supported, and the matched group will be extracted from the path and available for plugins consumption.
lena-larionova marked this conversation as resolved.
Show resolved Hide resolved
* **Escaping special characters:** When configuring Routes with regex paths via the Admin API, be sure to URL encode your payload if necessary according to [RFC 3986](https://tools.ietf.org/html/rfc3986).
* **Normalization behavior:** To prevent trivial Route match bypass, the incoming request URI from client
is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986)
before router matching occurs. Specifically, the following normalization techniques are
used for incoming request URIs, which are selected because they generally don't change
semantics of the request URI:
1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`.
2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`.
3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`.
4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`.

Regex Route paths only use methods 1 and 2. In addition, if the decoded character becomes a regex meta character, it will be escaped with backslash.

### Priority matching

If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. How Routes are prioritized depends on the router mode you're using.

#### Traditional compatibility mode

In `traditional_compat` mode, the priority of a Route is determined as
follows, by the order of descending significance:

1. **Priority points:** For the presence of each of a Route's `methods`, `host`, `headers`, and `snis`, a "priority point" is added. The number of "priority points" determines the overall order in which the Routes will be considered. Routes with higher "priority point" values will be considered before those with lower values. This means that if one Route has `methods` defined, and second one has `methods` and `headers` defined, the second one will be considered before the first one.
2. **Wildcard hosts:** Among Routes with the same "priority point" value, those that have any wildcard host specification will be considered after those that don't have any wildcard host (or no host) specified.
3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers.
4. **Regular expressions and prefix paths:** Within the resulting groups of Routes with equal priority, the router sorts them as follows:
- Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes with a higher `regex_priority` are considered before those with lower `regex_priority` values.
- Routes that have no regular expression path are ordered by the length of their paths. Routes with longer paths are considered before those with shorter paths.

For a Route with multiple paths, each path will be considered separately for priority determination. Effectively, this means that separate Routes exist for each of the paths.

#### Expressions router mode

In [`expressions` mode](/gateway/routing/expressions/) when a request comes in, {{site.base_gateway}} evaluates Routes with a higher `priority` number first. The priority is a positive integer that defines the order of evaluation of the router. The larger the priority integer, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined.
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

### Routing performance recommendations

You can use the following recommendations to increase routing performance:

* In `expressions` mode, we recommend putting more likely matched Routes before (as in, higher priority) those that are less frequently matched.
* Regular expressions in Routes use more resources to evaluate than simple prefixes. In installations with thousands of Routes, replacing regular expression with simple prefix can improve throughput and latency of {{site.base_gateway}}. If regex must be used because an exact path match must be performed, using the [expressions router](/gateway/routing/expressions/) will significantly improve {{site.base_gateway}}’s performance in this case.
cloudjumpercat marked this conversation as resolved.
Show resolved Hide resolved

## Schema

Expand Down
32 changes: 0 additions & 32 deletions app/_gateway_entities/target.md

This file was deleted.

43 changes: 0 additions & 43 deletions app/_gateway_entities/upstream.md

This file was deleted.

87 changes: 87 additions & 0 deletions app/_how-tos/rewrite-simple-request-urls-with-routes.md
lena-larionova marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: Rewrite simple request URLs with {{site.base_gateway}} Routes
content_type: how_to
related_resources:
- text: Routes
url: /gateway/entities/route/
- text: Services
url: /gateway/entities/service/
- text: Routing in {{site.base_gateway}}
url: /gateway/routing/

products:
- gateway

works_on:
- on-prem
- konnect

tools:
- deck

prereqs:
entities:
services:
- example-service

entities:
- service
- route

tags:
- routing
- traffic-control

tldr:
q: How can I divert traffic from an old URL to a new one with {{site.base_gateway}}?
a: Create a new route and point it to the existing Gateway Service. The new route will proxy traffic to the existing service at the new URL.

faqs:
- q: My URLs are more complex, such as replacing `/api/<function>/old` with `/new/api/<function>`, what should I use instead to rewrite them?
a: You can use either the [Request Transformer plugin](/plugins/request-transformer/) or the [expressions router](/gateway/routing/expressions/) for complex URLs.

cleanup:
inline:
- title: Clean up Konnect environment
include_content: cleanup/platform/konnect
icon_url: /assets/icons/gateway.svg
- title: Destroy the {{site.base_gateway}} container
include_content: cleanup/products/gateway
icon_url: /assets/icons/gateway.svg
---

## 1. Set up a Route with the path to the new Upstream

In the prerequisites, you created the `example-service` pointing to the `/anything` upstream. This path, `/anything`, is your old upstream path. You must create a Route with your new path, `/new-path`, that points to the new Upstream. By doing it this way, traffic can continue to be routed to the old path while you enable the new path.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In the prerequisites, you created the `example-service` pointing to the `/anything` upstream. This path, `/anything`, is your old upstream path. You must create a Route with your new path, `/new-path`, that points to the new Upstream. By doing it this way, traffic can continue to be routed to the old path while you enable the new path.
Create a Route with your new path, `/new-path`, that points to the upstream established in the `example-service`. By doing it this way, incoming traffic uses the `/new-path` route to access the upstream application, instead of directly accessing the `/anything` path.

This is a bit difficult to rephrase, because this is essentially the core of what Routes do in Kong.


{% entity_examples %}
entities:
routes:
- name: new-route
paths:
- "/new-path"
service:
name: example-service
{% endentity_examples %}

## 2. Apply configuration

{% include how-tos/steps/apply_config.md %}

## 3. Validate

To validate that the URL was successfully rewritten and the request is now being matched to the new Upstream instead of the old one, run the following:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To validate that the URL was successfully rewritten and the request is now being matched to the new Upstream instead of the old one, run the following:
To validate that the URL was successfully rewritten, run the following:

The upstream remains the same. They are simply accessing it via a different path. That is, if you go to https://httpbin.org/anything and compare it to the output of http://localhost:8000/new-path from this example, they are the same thing.


```bash
curl -i http://localhost:8000/new-path
```
{: data-deployment-topology="on-prem" }

```bash
curl -i http://{host}/new-path
```
{: data-deployment-topology="konnect" }
Replace `{host}` with the proxy URL for this data plane node.
{: data-deployment-topology="konnect" }

This command should display a 200 status as you're redirected to the new URL. In the response, you'll also see that `"Host": "httpbin.konghq.com",` as the request is proxied to the new URL.
Loading
Loading