T246379 resulted in a list of candidates for an API router, among them [[ https://www.envoyproxy.io | Envoy ]]. Since Envoy is already in use at the foundation, we should be particularly thorough in determining its feasibility. Where gaps exist, we should establish what sort of extensions would be required to satisfy requirements.
----
### Evaluation
#### Routing requests
The routes we require will generally take the form `api.wm.o/{something}/v{version}/{project}/{lang}/{path}` → `{lang}.{project}.org/{...}`; We need to parse language and project from the source URL, and use it to construct a destination hostname. Envoy has no native means of supporting this.
Our test configuration uses the Lua HTTP filter to parse the URL, string format the destination hostname, and inject a new HTTP header, `X-Internal-Host`. During routing, the `auto_host_rewrite_header` is used to substitute the destination hostname with the value of `X-Internal-Host` (see snipet below).
```lang=yaml
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
safe_regex:
google_re2: {}
regex: "^/core/v\\d{1}/wikipedia/en/.*$"
route:
regex_rewrite:
pattern:
google_re2: {}
regex: ".*\/([^\/]+)\/wikipedia\/([^\/]+)(\/.*)$"
substitution: /w/rest.php/\1\3
auto_host_rewrite_header: "x-internal-host"
cluster: service_echoapi
- match:
prefix: "/"
route:
host_rewrite: www.google.com
cluster: service_echoapi
http_filters:
- name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.config.filter.http.lua.v2.Lua
inline_code: |
function envoy_on_request(request_handle)
local path = request_handle:headers():get(":path")
project, lang = string.match(path, "^/%a+/v%d/(%a+)/(%a+)/.*$")
request_handle:headers():add("x-internal-host", lang .. "." ..project .. ".org")
end
- name: envoy.filters.http.router
```
This works, and despite seeming hacky, seems to be endorsed upstream.
It is not clear what the performance impact of using Lua to pattern match like this would be.
Any improvements would require coding (e.g. forking the filter if the changes cannot be pushed upstream, and/or creating a custom filter to perform the match).
#### Parsing rate limit values from JWT
(IMPORTANT) TODO: Do.
#### Rate limiting
(IMPORTANT) TODO: Do.
----
See also: https://github.com/eevans/wmf-api-gateway — a test/dev environment using Docker Compose.