Inject response header
What if you require a routing policy to inject a header from an inbound request into a response header?
Setup
This guide assumes that you installed the following components:
- Gloo Gateway in the
gloo-system
namespace in your cluster - The
glooctl
command line utility - The jq command line utility to format JSON strings
You also need an upstream service to serve as the target for the requests that you send to test the Gloo Gateway configurations in this tutorial. You can use the publicly available Postman Echo service. Postman Echo exposes a set of endpoints that are very useful for inspecting both the requests sent upstream and the resulting responses. For more information about this service, see the Postman Echo documentation.
Create a static upstream to represent the postman-echo.com remote service.
apiVersion: gloo.solo.io/v1
kind: Upstream
metadata:
name: postman-echo
namespace: gloo-system
spec:
static:
hosts:
- addr: postman-echo.com
port: 80
Let’s also create a simple Virtual Service that matches any path and routes all traffic to our Upstream:
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: inject-response-header
namespace: gloo-system
spec:
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: /
routeAction:
single:
upstream:
name: postman-echo
namespace: gloo-system
Let’s test that the configuration was correctly picked up by Gloo Gateway by executing the following command:
curl -v -H "x-solo-hdr1: val1" $(glooctl proxy url)/get -i
You should get a response with status 200
and a JSON body similar to the one below. Note that the x-solo-hdr1
header is in the payload response from postman-echo, but it is not included in the response headers reported by curl.
HTTP/1.1 200 OK
date: Thu, 03 Mar 2022 22:29:21 GMT
content-type: application/json; charset=utf-8
content-length: 349
vary: Accept-Encoding
x-envoy-upstream-service-time: 42
server: envoy
{"args":{},"headers":{"x-forwarded-proto":"http","x-forwarded-port":"80","host":"35.185.51.108","x-amzn-trace-id":"Root=1-62214141-5de08d0b3bae549e7cea830e","user-agent":"curl/7.77.0","accept":"*/*","x-solo-hdr1":"val1","x-request-id":"3ab8790f-d392-4e37-93f1-ecb0e0d6ce41","x-envoy-expected-rq-timeout-ms":"15000"},"url":"http://35.185.51.108/get"}
Injecting the response header
As you can see from the response above, the upstream service echoes the JSON payload we included in our request inside the data
response body attribute. We will now configure Gloo Gateway to change the response status to 400 if the data.error
attribute is present; otherwise, the original status code should be preserved.
Update the Virtual Service
To implement this behavior, we need to add a responseTransformation
stanza to our original Virtual Service definition. Note that the request_header
function is used in an Inja template to extract the value of the x-solo-hdr
header from the request. Then it injects that value into a new response header x-solo-resp-hdr1
.
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
name: inject-response-header
namespace: gloo-system
spec:
virtualHost:
domains:
- '*'
routes:
- matchers:
- prefix: /
routeAction:
single:
upstream:
name: postman-echo
namespace: gloo-system
options:
transformations:
responseTransformation:
transformationTemplate:
headers:
x-solo-resp-hdr1:
text: '{{ request_header("x-solo-hdr1") }}'
Test the modified configuration
We’ll test our modified Virtual Service by issuing the same curl command as before:
curl -H "x-solo-hdr1: val1" $(glooctl proxy url)/get -i
This should yield something similar to the following output. Note that in the curl response, there is a new response header: x-solo-resp-hdr1: val1
HTTP/1.1 200 OK
date: Thu, 03 Mar 2022 22:40:27 GMT
content-type: application/json; charset=utf-8
content-length: 349
vary: Accept-Encoding
x-envoy-upstream-service-time: 45
x-solo-resp-hdr1: val1
server: envoy
{"args":{},"headers":{"x-forwarded-proto":"http","x-forwarded-port":"80","host":"35.185.51.108","x-amzn-trace-id":"Root=1-622143db-7397fdb03f893d082bfa5028","user-agent":"curl/7.77.0","accept":"*/*","x-solo-hdr1":"val1","x-request-id":"ea032e6b-5536-49b9-a5d6-55f70bf480a5","x-envoy-expected-rq-timeout-ms":"15000"},"url":"http://35.185.51.108/get"}
Congratulations! You have successfully used a response transformation to inject the value of a request header into a new response header.
Cleanup
To cleanup the resources created in this tutorial you can run the following commands:
kubectl delete virtualservice -n gloo-system inject-response-header
kubectl delete upstream -n gloo-system postman-echo