# Routing

Routing pertains to the path one request should take to get from a client to a specified endpoint. In Grey Matter, this is configured through Domains and Clusters.

For each Grey Matter [domain](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/domain), a [virtual host](https://www.envoyproxy.io/docs/envoy/v1.15.0/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-virtualhost) will be created from a combination of the domain configuration as well as any Grey Matter [route](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route) object that routes to it. Each route object is also linked to a Grey Matter [shared rules](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/shared_rules) object, which determines the default Grey Matter [cluster](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/cluster) to send the incoming request to.

The link between domain, route, and shared rules is important. A request is sent to a domain based on its *Host* or *:authority* header. From there, each route on the virtual host for that domain is checked in order for a "match" (see [path matching](#path-matching)). Once a match is found, the request is forwarded to a cluster. This cluster will be determined either by the shared rules default configuration linked to that route, or by the [routing rules](#rules) `constraints` field. See [route forwarding](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/traffic_control/route_forwarding) for these configuration specifics.

## Table of Contents

* [Table of Contents](#table-of-contents)
* [Configuration Reference](#configuration-reference)
* [Example Object](#example-object)
* [Path Matching](#path-matching)
* [Prefix Rewriting](#prefix-rewriting)
* [Redirect](#redirect)
* [Rules](#rules)
  * [Method Match](#method-match)
  * [Header Match](#header-match)
  * [Cookie Match](#cookie-match)
  * [Query Parameter Match](#query-parameter-match)
* [Retry Policies](#retry-policies)
* [Per Route Filter Configuration](#per-route-filter-configuration)
  * [`filter-metdata` (deprecated)](#filter-metdata-deprecated)

## Configuration Reference

| Attribute              | Description                                                                                                                                                                      | Type                                                                                                                          | Default |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------- |
| `shared_rules.default` | Defines the types of traffic the shared rules will serve to the specified upstream clusters.                                                                                     | `JSON` map of constraintType : `constraint`                                                                                   | `{}`    |
| `shared_rules.rules`   | List of [rules](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/shared_rules/rule) applied to to decide to the upstream cluster target | Array of [rules](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/shared_rules/rule) | `[]`    |
| `route.rules`          | List of [rules](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route/rule) applied to to decide to the upstream cluster target        | Array of [rules](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route/rule)        | `[]`    |
| `route.route_match`    | The pathname for a given route, which the request must match                                                                                                                     | `string`                                                                                                                      | `""`    |
| `route.prefix_rewrite` | The updated URL on the outgoing request                                                                                                                                          | `string`                                                                                                                      | `""`    |
| `domain.redirects`     | Redirection configuration for routes on the same host                                                                                                                            | Array of redirects                                                                                                            | `[]`    |

## Example Object

The Grey Matter [route object](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route) is used to configure [Envoy's HTTP routing](https://www.envoyproxy.io/docs/envoy/v1.15.0/api-v3/config/route/v3/route.proto#http-route-configuration) for a virtual host. The minimal route object looks something like the following:

```javascript
{
  "route_key": "example-route",
  "domain_key": "example-domain",
  "zone_key": "zone-default-zone",
  "path": "",
  "route_match": {
    "path": "/services/example/latest/",
    "match_type": "prefix"
  },
  "prefix_rewrite": "/",
  "redirects": null,
  "shared_rules_key": "example-shared-rules",
  "rules": null,
  "response_data": {},
  "cohort_seed": null,
  "retry_policy": null,
  "high_priority": false,
}
```

The `domain_key` explicitly links this route to a specific domain, and the `shared_rules_key` does the same for shared rules. When a request is sent to the Grey Matter domain matching this `domain_key`, the route configured from this object will be on the list of routes to be considered for a match. If a request is matched to this route, the request will be sent to a cluster as determined by the shared rules object given by `"shared_rules_key"` unless specified otherwise in the route's [rules](#routing-rules).

## Path Matching

When a request is sent to a particular domain, each route on the virtual host for that domain is checked in order for a match on its *:path* header. Once a match is found, the route is used. In order for a request to be considered a "match" for a route, it must meet whatever matching criteria is configured in the route object. In the most basic case, this requires path matching.

Path matching is configured using the [`route_match`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route#route_match) field in the route object. This field takes two values, `path` and `match_type`. If the *:path* header on the incoming request matches whatever the `route_match.path` is, based on the `route_match.match_type`, this path is considered a "match".

See the [routing example](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route).

There are options to create more complex matching criteria, including matching specific headers, cookies, etc. These extra matching rules can be set using [routing rules](#rules).

## Prefix Rewriting

When a route is matched to a request, there is an option to change the value of the *:path* header on the request before directing the request to the cluster.

Prefix rewriting is configured on a route in the [`prefix_rewrite`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route#prefix_rewrite) field. When a request is matched to the route, the *:path* that the request came in on will be rewritten, replacing the matched `route_match` value with the string value of `prefix_rewrite`.

For example, if the *:path* header for an incoming request to the `example-domain` is `"/services/examples/latest/ping"`, the route created by the [example object](#example-object) will be considered a match. At this point in time the request *:path* will altered by replacing the `route_match.path`, which is `"/services/example/latest/"`, with the `prefix_rewrite` value, which is `"/"`. Thus, the *:path* on the request will now be `"/ping"` when it is forwarded to the cluster.

This is particularly necessary in a service mesh, where requests are rarely sent directly to their destination service.

## Redirect

Redirects are supported on both domain and route objects for convenience. Both have the same syntax: The [`redirects`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/domain#redirects) top-level key on a domain or route is an array of redirect objects:

```javascript
"redirects": [
    {
      "name": ""
      "from": "^/services/drive-data/2\\.0\\.0$",
      "to": "/services/drive-data/2.0.0/",
      "redirect_type": "permanent",
      "header_constraints": null
    }
]
```

The new route (implicitly generated from each redirect) will have its [path matching](#path-matching) specification with match type `regex` for the value configured in the `redirect.from` field. The route will redirect to the url given by the `redirect.to` value, with response code set as either `307` for Temporary Redirect or `308` for Permanent Redirect, as configured with `redirect_type`.

For redirects on a route object, the `name` field is optional, defaulting to `""`, and collisions cause no trouble due to the parent route scoping. There is also the option to set header matchers on the redirect route. The `header_constraints` field takes a list of header constraint objects, and each constraint in this list will be used to configure an Envoy [header matcher](https://www.envoyproxy.io/docs/envoy/v1.15.0/api-v2/api/v2/route/route_components.proto#route-headermatcher) on the route. This means that, before an incoming request will be considered a match for the route, it **also must** match each of these header constraints. First, the incoming requests headers will checked for the existence of the header with key equal to the `name` field of the header constraint. If the header exists, its value will be regex compared with the `value` field of the header constraint. If this value is equal, the header match is considered a match. If and only if the incoming request path matches and route and matches every header constraint set on the route is the request considered a match.

One very common reason for adding a redirect to an existing route is to support paths with and without a trailing slash. The following example creates a route with a trailing slash, and uses `redirects` in the same object to add a redirect from the version of the route without the trailing slash to the version *with* a trailing slash.

```javascript
{
  "route_key": "edge-to-data-route",
  "domain_key": "edge",
  "zone_key": "zone-default-zone",
  "shared_rules_key": "edge-to-data-shared-rules",
  "route_match": {
    "path": "/services/drive-data/2.0.0/",
    "match_type": "prefix"
  },
  "prefix_rewrite": "/",
  "redirects": [
    {
      "from": "^/services/drive-data/2\\.0\\.0$",
      "to": "/services/drive-data/2.0.0/",
      "redirect_type": "permanent"
    }
  ]
}
```

## Rules

A `rule` set on a [route](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route#rules) or [shared rules](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/shared_rules#rules) can be used to specify the cluster that a route should send requests to. To do this, set the `constraints` key in the rules field for the desired cluster as described in [route forwarding](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/traffic_control/route_forwarding).

Adding additional, more complex specifications for a route match can also be configured using the `methods` and `matches` fields of the rules object. These can be used to configure additional constraints to be added to the route that a request must also meet in order to be considered a match.

The `methods` field can be used to configure [method matching](#method-match) on the route. The `matches` field in the rules object allows for the addition of specific [header](#header-match), [cookie](#cookie-match), or [query parameter](#query-parameter-match) matchers to the route match. This field takes a list of `match` objects to add a series of these constraints.

Additionally, rules can be used to configure [metadata matching](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match) for using load balancer subsets on the upstream cluster and it's routes.

### Method Match

The `methods` field takes a list of values which will be matched against the method of the incoming request. If one value is provided, the match will be an exact match. If more than one is provided, the match will be a regex match to a pipe delimited list of the `methods` values. If `methods` are configured, the incoming request will be considered a match only if its method matches those configured here.

### Header Match

A header matcher rule on the route will look for a specific header on the incoming request and compare it's value to a configured value. To configure a header match in the `matches` field as follows:

* `match.kind` set to `"header"`
* `match.from.key` set to the name of the header to check the incoming request for
* `match.from.value` set to value to compare to the value of the header in the request with key `match.from.key`
* `match.to.key`
  * *not currently supported*
  * if configured, sets up a [metadata match](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match) for the upstream cluster
  * required if `match.to.value` is set
* `match.to.value`
  * *not currently supported*
  * see [metadata match](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match)

> Note: if the `match.from.value` is a valid regex, regex matching will be used. Otherwise, it will be exact match.

### Cookie Match

To configure a header matcher rule for a cookie on the route, configure a match in the `matches` field as follows:

* `match.kind` set to `"cookie"`
* `match.from.key` set to the name of the cookie to check the incoming request's cookies for
* `match.from.value` set to the value to compare to the value of the cookie in the request with key `match.from.key`
* `match.to.key`
  * *not currently supported*
  * if configured, sets up a [metadata match](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match) for the upstream cluster
  * required if `match.to.value` is set
* `match.to.value`
  * *not currently supported*
  * see [metadata match](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match)

> Note: for a cookie match, the match type will always be regex

If `match.from.value` is left empty, a wildcard cookie match will be used.

### Query Parameter Match

To configure a [query parameter matcher](https://www.envoyproxy.io/docs/envoy/v1.15.0/api-v2/api/v2/route/route_components.proto#route-queryparametermatcher) on the route, configure a match in the `matches` field as follows:

* `match.kind` set to `"query"`
* `match.from.key` set to the name of the query parameter to check the incoming request's query string for
* `match.from.value` set to the value to compare to the value of the query parameter in the request with key `match.from.key`
* `match.to.key`
  * *not currently supported*
  * if configured, sets up a [metadata match](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match) for the upstream cluster
  * required if `match.to.value` is set
* `match.to.value`
  * *not currently supported*
  * see [metadata match](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/route_forwarding#metadata-match)

## Retry Policies

A retry policy can be implemented on a route in the [`retry_policy`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route#retry-policy) field.

See the [Retry Policy](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/usage/traffic_control/resilience/retry) documentation.

## Per Route Filter Configuration

The route object field [`filter_configs`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route#filter-metadata) can be used to set [Grey Matter filters](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http) on specific routes.

Example:

```javascript
"filter_configs": {
  "gm.observables": {
    "emitFullResponse": true
  },
  "gm.oidc-validation": {
    "enforce": true,
    "enforceResponseCode": 401
  }
}
```

Filters that currently support per route configurations are:

* [`gm.observables`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http/gm-observables)
* [`gm.oidc-validation`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http/gm-oidc-validation)
* [`gm.metrics`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http/gm-metrics)
* [`gm.listauth`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http/gm-listauth)
* [`gm.oauth`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http/gm-oauth)
* [`envoy.buffer`](https://www.envoyproxy.io/docs/envoy/v1.15.0/api-v3/extensions/filters/http/buffer/v3/buffer.proto#envoy-v3-api-msg-extensions-filters-http-buffer-v3-bufferperroute)
* [`envoy.ext_authz`](https://www.envoyproxy.io/docs/envoy/v1.15.0/configuration/http/http_filters/ext_authz_filter#per-route-configuration)
* [`envoy.filters.http.rbac`](https://www.envoyproxy.io/docs/envoy/v1.15.0/configuration/http/http_filters/rbac_filter#per-route-configuration)

See the [per route filter configuration guide](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/guides/fabric-guides/per-route-filter-config) for an example.

### `filter-metdata` (deprecated)

**Note** This method of configuring filters at the route level is deprecated may not be supported in the next major release. Use `filter_configs` instead (see above).

The route object field [`filter_metadata`](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/route#filter-metadata) can be used to set [Grey Matter filters](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/filters/http) on specific routes.

The `filter_metadata` takes a map from the name of the filter to configure for the route, and the corresponding key, value pair should indicate the filter configuration field and the value to set it to. Note that the filter being customized has to be active in the [listener](https://greymatter.gitbook.io/grey-matter-documentation/1.7-beta/reference/api/fabric-api/listener) active filters for the service in order to set per route configurations. The `filter_metadata` configuration will look like the following:

```javascript
"filter_metadata": {
  "<filter-name>": [
    {
      "key": "<filter configuration key to set value for>",
      "value": "<desired value of key>"
    }
  ]
}
```

All filters listed above support this; however, the only values that can be configured are string "key": "value" pairs.
