Skip to content

Commit 9b70c83

Browse files
authored
Merge pull request #77 from sevenval/45527-x-flat-proxy
45527 x flat proxy
2 parents fa2478f + c8ec786 commit 9b70c83

File tree

8 files changed

+214
-12
lines changed

8 files changed

+214
-12
lines changed

cookbook/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
## [How can I pass an arbitrary header field to an upstream system?](pass-header-field-upstream.md)
66

7-
## [Forwarding a Request to an Upstream API](forward-request-upstream.md)
7+
## [Proxying Requests to Upstream APIs (Swagger)](proxy-requests.md)
8+
9+
## [Forwarding a Request to an Upstream API (Flow)](forward-request-upstream.md)
810

911
## [How can I pass response headers to the client?](pass-header-field-downstream.md)
1012

cookbook/forward-request-upstream.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ The following [flow](/reference/flow.md) shows a more advanced example:
2222
<flow>
2323
<proxy-request>
2424
{
25-
{{// Replace the hostname of the incoming request with the UPSTREAM_URI environment variable }}
26-
"url": {{ replace($request/url, "^http://[^/]+", $env/UPSTREAM_URI) }},
25+
{{// Replace the origin of the incoming request with the UPSTREAM_ORIGIN environment variable }}
26+
"origin": {{ $env/UPSTREAM_ORIGIN }},
2727

2828
"headers": {
2929
{{// Set X-tra, drop X-Remove, copy Authorization }}
@@ -42,7 +42,7 @@ The following [flow](/reference/flow.md) shows a more advanced example:
4242
</flow>
4343
```
4444

45-
The `proxy-request` action lets you set the `url` and modify the `headers` of the request.
45+
The `proxy-request` action lets you set the `origin` and modify the `headers` of the request.
4646
Everything else is set up automatically: The client request body will be forwarded
4747
as-is, any headers not intended for upstream will be dropped.
4848

@@ -103,7 +103,31 @@ status code of the upstream response and possibly additional header fields are c
103103
The forwarded request will only have a body if the incoming request does.
104104
The `Content-Type` request and response headers are passed automatically with the body, therefore we don't have to copy them explicitly.
105105

106+
If the client and the upstream request URL paths do not share a common prefix, you can easily adjust the path by using `stripEndpoint` and `addPrefix`:
107+
108+
```json
109+
{
110+
"origin": {{ $env/UPSTREAM_ORIGIN }},
111+
"stripEndpoint: true,
112+
"addPrefix": {{ $env/UPSTREAM_PATH_PREFIX }},
113+
114+
}
115+
```
116+
117+
Assuming the following `swagger.yaml` for `https://client.example.com/`
118+
119+
```yaml
120+
basePath: /api
121+
paths:
122+
/users/**:
123+
124+
```
125+
126+
, `https://users.upstream.example.com` for `UPSTREAM_ORIGIN`, and `/v4` for `UPSTREAM_PATH_PREFIX`, a client request for `https://client.example.com/api/users/profile` will be forwarded to `https://users.upstream.example.com/v4/profile`.
127+
128+
106129
## See also
107130

131+
* [Proxying requests to Upstream APIs](proxy-requests.md) (cookbook)
108132
* [`proxy-request` action](/reference/actions/proxy-request.md) (reference)
109133
* [`request` action](/reference/actions/request.md) (reference)

cookbook/proxy-requests.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Proxying requests to Upstream APIs
2+
3+
To proxy requests to an upstream API, you can simply use a combination of two FLAT Swagger enhancements:
4+
5+
* [wildcard paths](/reference/OpenAPI/differences.md#wildcard-paths), and
6+
* [`x-flat-proxy`](/reference/OpenAPI/routing.md#assigning-flat-proxies).
7+
8+
Imagine, the upstream API, you want to use, is located at `https://upstream.api/api/docs` and provides a route to get a document with a certain ID (`/get-doc/{docid}`). To set FLAT as a proxy to this API, the following `swagger.yaml` snippet will do the job:
9+
10+
```yaml
11+
12+
basePath: /api
13+
14+
paths:
15+
/docs/**:
16+
x-flat-proxy:
17+
origin: https://upstream.api # replaces the origin
18+
19+
```
20+
21+
22+
Assuming a client origin of `https://client.example.com`, a client request to e.g. `https://client.example.com/api/docs/get-doc/42` will be proxied to `https://upstream.api/api/docs/get-doc/42`.
23+
24+
Note, that only the origin is replaced, the path is not modified.
25+
26+
If the upstream API for docs is located at `https://docs.upstream.api/v4` instead of `https://upstream.api/api/docs`, the path has to be adjusted, too:
27+
28+
```yaml
29+
30+
basePath: /flat
31+
32+
paths:
33+
/docs/**:
34+
x-flat-proxy:
35+
origin: https://docs.upstream.api
36+
stripEndpoint: true # strips /flat/docs from the path
37+
addPrefix: /v4 # inserts /v4 before the stripped path
38+
39+
```
40+
41+
The client request will be proxied to `https://docs.upstream.api/v4/get-doc/42`.
42+
43+
Assuming you want to plug-in a different API (`https://users.upstream/v3`), just add the following:
44+
45+
```yaml
46+
47+
/users/**:
48+
x-flat-proxy:
49+
origin: https://users.upstream.api
50+
stripEndpoint: true # strips /flat/users from the path
51+
addPrefix: /v3 # inserts /v3 before the stripped path
52+
```
53+
54+
A client request to `https://client.example.com/flat/users/profile/4711` will be proxied to `https://users.upstream.api/v3/profile/4711`.

reference/OpenAPI/differences.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ First of all, several extensions named `x-flat-…` are recognized on different
99
* `x-flat-flow`: [flow](routing.md#assigning-flat-flows) to be started. Recognized at top-level and below `paths`, `paths/<path>` and `paths/<path>/<operation>`.
1010
* `x-flat-init`: [init flow](routing.md#init-flow) (top-level)
1111
* `x-flat-error`: [error flow](routing.md#error-flow) (top-level)
12+
* `x-flat-proxy`: [proxy configuration](routing.md#assigning-flat-proxies) (below `paths`, `paths/<path>` and `paths/<path>/<operation>`)
1213
* `x-flat-cors`: [CORS configuration](cors.md) (top-level)
1314
* `x-flat-validate`: [validation](validation.md) (top-level, below `paths/<path>` and `paths/<path>/<operation>`)
1415
* `x-flat-jwt`: [expected JWT](security.md#the-x-flat-jwt-field) (in a [security scheme object](https://swagger.io/specification/v2/#securitySchemeObject))

reference/OpenAPI/routing.md

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ paths:
100100

101101
### Init Flow
102102

103-
An _init flow_ is a separate flow file that is executed before the regular [flow](/reference/flow.md)
104-
that is defined for an API path. It is specified by setting `x-flat-init` on
103+
An _init flow_ is a separate flow file that is executed before the regular [flow](/reference/flow.md) or [configured proxy](routing.md#assigning-flat-proxies) defined for an API path. It is specified by setting `x-flat-init` on
105104
the top level in the OpenAPI definition:
106105

107106
```yaml
@@ -129,7 +128,7 @@ flow from being executed, too.
129128

130129
### Error Flow
131130

132-
An _error flow_ is an optional separate flow file that is executed if a client request or response validation error has occurred, or if the `exit-on-error` option was set for a [request](/reference/actions/request.md) that has failed.
131+
An _error flow_ is an optional separate flow file that is executed if a client request or response validation error has occurred, or if the `exit-on-error` option was set for a [request](/reference/actions/request.md), [proxy-request](/reference/actions/proxy-request.md) or [configured proxy](routing.md#assigning-flat-proxies) that has failed.
133132
It is specified by setting the `flow` property of `x-flat-error` on the top level in the OpenAPI definition:
134133

135134
```yaml
@@ -147,6 +146,41 @@ Requests to resources outside the `basePath` are handled by the default flow def
147146
in `conf/flow.xml`. This allows for [serving HTML, images, JavaScript](/cookbook/file-serving.md) and the like.
148147

149148

149+
## Assigning FLAT Proxies
150+
151+
If FLAT acts as a proxy for an upstream API on a specific route, you could assign a flow containing a [`proxy-request` action](/reference/actions/proxy-request.md).
152+
153+
A simpler way to achieve this is by using `x-flat-proxy` in the `swagger.yaml`:
154+
155+
```yaml
156+
basePath: /api
157+
paths:
158+
/users/**:
159+
x-flat-proxy:
160+
origin: https://users.upstream.example.com
161+
stripEndpoint: true
162+
addPrefix: /v4
163+
headers:
164+
Correlation-ID: 42
165+
options:
166+
timeout: 2
167+
exit-on-error: true
168+
definition: users-upstream.yaml
169+
validate-request: true
170+
validate-response: true
171+
```
172+
173+
A client request to `https://client.example.com/api/users/profile` will be proxied to `https://users.upstream.example.com/v4/profile`. See [wildcard paths](differences.md#wildcard-paths) for more information about `/**`.
174+
175+
`x-flat-proxy` can be used below `paths`, `paths/<path>` and `paths/<path>/<operation>`.
176+
177+
The configuration for `x-flat-proxy` is the same as that for a [`proxy-request` action](/reference/actions/proxy-request.md) (translated from JSON to YAML syntax).
178+
179+
If configured, the [init flow](routing.md#init-flow) is executed before the proxy request. If configured, the [error flow](routing.md#error-flow) is executed if the `exit-on-error` option was set and the proxy request fails.
180+
181+
`x-flat-proxy` and `x-flat-flow` are alternatives and cannot be used in combination.
182+
183+
150184
## Path Parameters
151185

152186
Swagger paths can define path parameters:

reference/OpenAPI/security.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ securityDefinitions:
4343
```
4444
The code in this example defines a security scheme named `JWTHeaderAuth`.
4545
The token is expected to be a bearer token in the `Authorization` header.
46-
The key is read from a file named `secret.pem` relative to the swagger.yaml.
46+
The key is read from a file named `secret.pem` relative to the `swagger.yaml`.
4747
The signing algorithm is read from the `FLAT_JWT_ALG` environment variable.
4848
The JWT will be stored in the `$header_token` variable.
4949
The JWT payload is expected to contain an `aud` claim with a value read from the `FLAT_JWT_AUDIENCE` environment variable.

reference/actions/proxy-request.md

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,34 @@ Just like an ordinary [`request`](request.md) the `proxy-request`
1818
can be configured using a [JSON template](/reference/templating/README.md)
1919
with the following properties:
2020

21+
### `origin`
22+
23+
Sets the origin of the upstream system. Either `origin` or `url` is required. Type: `string`.
24+
25+
### `stripEndpoint`
26+
27+
To be used in connection with `origin`. If `true`, strips the endpoint path from the client request URL path before it is added to the upstream origin. Type: `boolean`, default: `false`
28+
29+
E.g.
30+
31+
```yaml
32+
basePath: /api
33+
paths:
34+
/foo/bar:
35+
/wildcard/**
36+
```
37+
38+
For the client request URL `https://client.example.com/api/foo/bar`, the path is stripped to `/`.
39+
40+
For the client request URL `https://client.example.com/api/wildcard/path/to`, the path is stripped to `/path/to`.
41+
42+
### `addPrefix`
43+
44+
Inserts a path prefix before the given (client request URL) path, after possible endpoint stripping (see `stripEndpoint`). Type: `string`.
45+
2146
### `url`
2247

23-
Sets the URL to the upstream system. Required.
48+
Sets the URL to the upstream system. Either `url` or `origin` is required.
2449

2550
### `headers`
2651

@@ -31,7 +56,44 @@ To remove a header, set its value to `""`.
3156

3257
Sets request options. See the [`request` action options](request.md#options) for valid options.
3358

34-
## Example
59+
## Examples
60+
61+
Using `origin`:
62+
63+
```xml
64+
<flow>
65+
<proxy-request>
66+
{
67+
"origin": "https://example.com",
68+
"stripEndpoint": true,
69+
"addPrefix": "/path/to/api",
70+
71+
"headers": {
72+
"X-API-Key": "foo42bar"
73+
},
74+
75+
"options": {
76+
"exit-on-error": true,
77+
"definition": "upstream.yaml",
78+
"validate-request": true,
79+
"validate-response": true
80+
}
81+
}
82+
</proxy-request>
83+
</flow>
84+
```
85+
86+
With the client request URL `http://client.example.com/my/api/foo/bar` matching the swagger definition path
87+
88+
```yaml
89+
basePath: /my/api
90+
paths:
91+
/foo/**:
92+
x-flat-flow: proxy.xml
93+
```
94+
the upstream request URL will be `https://example.com/path/to/api/bar`.
95+
96+
Using `url`:
3597

3698
```xml
3799
<flow>

reference/variables.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ Example:
172172
<host>localhost</host>
173173
<port>12345</port>
174174
<id>XeeSVJ5AFt8VyXYagp3lvgAAACc</id>
175-
<url>http://localhost:12345/api/proxy?a=b&amp;c=d</url>
176-
<path>/api/proxy</path>
175+
<url>http://localhost:12345/api/proxy/foo?a=b&amp;c=d</url>
176+
<path>/api/proxy/foo</path>
177177
<query>a=b&amp;c=d</query>
178178
<headers>
179179
<host>localhost:12345</host>
@@ -193,6 +193,7 @@ Example:
193193
<NAME1>VALUE1</NAME1>
194194
<NAME2>VALUE2</NAME2>
195195
</cookies>
196+
<endpoint>/api/proxy</endpoint>
196197
</request>
197198
```
198199

@@ -202,6 +203,30 @@ As HTTP request headers are defined to be case-insensitive, their names are lowe
202203
$request/headers/user-agent
203204
```
204205

206+
If a client URL path is matched by a [wildcard path](/reference/OpenAPI/differences.md#wildcard-paths), `$request/endpoint` is the path part preceding the part matched by `/**`. Otherwise, `$request/endpoint` is the same as `$request/path`.
207+
208+
```yaml
209+
210+
basePath: /api
211+
212+
paths:
213+
/**:
214+
215+
/foo/**:
216+
217+
/foo/qux:
218+
219+
/foo/{p1}:
220+
221+
```
222+
223+
| Client URL | matches | `$request/path` | `$request/endpoint` |
224+
| --- | --- | --- | --- |
225+
| https://example.com/api/foo/qux | /foo/qux | /api/foo/qux | /api/foo/qux |
226+
| https://example.com/api/foo/quuux | /foo/{p1} | /api/foo/quuux | /api/foo/quuux |
227+
| https://example.com/api/foo/bar/qux | /foo/** | /api/foo/bar/qux | /api/foo |
228+
| https://example.com/api/bar | /** | /api/bar | /api |
229+
205230

206231
## `$error`
207232

0 commit comments

Comments
 (0)