Extract query parameters

In this tutorial we will see how to extract query parameters from a request and use them in a transformation.

Setup

This guide assumes that you have installed Gloo into the gloo-system namespace and that glooctl is installed on your machine. We will also use the jq command line utility to pretty print JSON strings.

We will need an upstream service to serve as the target for the requests that we will send to test the Gloo configurations in this tutorial. To this end, we will use the publicly available Postman Echo service. It exposes a set of endpoints that are very useful for inspecting both the requests sent upstream and the resulting responses; please refer to the official documentation for more information about the service.

Let’s 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: extract-query-params
  namespace: gloo-system
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matcher:
        prefix: /
      routeAction:
        single:
          upstream:
            name: postman-echo
            namespace: gloo-system

glooctl create vs --name extract-query-params --namespace gloo-system 
glooctl add route --name extract-query-params --path-prefix / --dest-name postman-echo

Let’s test that the configuration was correctly picked up by Gloo by executing the following command:

curl $(glooctl proxy url)/get | jq

You should get a response with status 200 and a JSON body similar to this:

{
  "args": {},
  "headers": {
    "x-forwarded-proto": "https",
    "host": "postman-echo.com",
    "accept": "*/*",
    "user-agent": "curl/7.54.0",
    "x-envoy-expected-rq-timeout-ms": "15000",
    "x-request-id": "db7eca70-630a-4aab-8e42-7ac3cfa064e8",
    "x-forwarded-port": "80"
  },
  "url": "https://postman-echo.com/get"
}

Update Virtual Service

As you can see from the response above, the upstream service returns the request headers as part of the JSON payload. We will now configure Gloo to extract the values of the foo and bar query parameters and use them to create two new headers named - you guessed it - foo and bar.

To implement this behavior, we need to add the following to our Virtual Service definition:

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: extract-query-params
  namespace: gloo-system
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matcher:
        prefix: /
      routeAction:
        single:
          upstream:
            name: postman-echo
            namespace: gloo-system
    virtualHostPlugins:
      transformations:
        requestTransformation:
          transformationTemplate:
            extractors:
              # This extracts the 'foo' query param to an extractor named 'foo'
              foo:
                # The :path pseudo-header contains the URI
                header: ':path'
                # Use a nested capturing group to extract the query param
                regex: '(.*foo=([^&]*).*)'
                subgroup: 2
              # This extracts the 'bar' query param to an extractor named 'bar'
              bar:
                # The :path pseudo-header contains the URI
                header: ':path'
                # Use a nested capturing group to extract the query param
                regex: '(.*bar=([^&]*).*)'
                subgroup: 2
            # Add two new headers with the values of the 'foo' and 'bar' extractions
            headers:
              foo:
                text: '{{ foo }}'
              bar:
                text: '{{ bar }}'

The above virtualHostPlugins configuration is to be interpreted as following:

  1. Add a transformation to all traffic handled by this Virtual Host.
  2. Apply the transformation only to requests.
  3. Define two extractions to extract the values of the query parameters. We achieve this by using regex capturing groups and selecting the nested group which matches only the value of the relevant query parameter.
  4. Add two headers and set their values of the values of the extractions.

Test our configuration

To test that our configuration has been correctly applied, let’s add the two expected query parameters to the previously used curl command:

curl "$(glooctl proxy url)/get?foo=foo-value&bar=bar-value" | jq

You should get the following output:

{
  "args": {
    "foo": "foo-value",
    "bar": "bar-value"
  },
  "headers": {
    "x-forwarded-proto": "https",
    "host": "postman-echo.com",
    "accept": "*/*",
    "bar": "bar-value",
    "foo": "foo-value",
    "user-agent": "curl/7.54.0",
    "x-envoy-expected-rq-timeout-ms": "15000",
    "x-request-id": "9dbe87fe-7ee8-4d47-b3e4-76c545515d33",
    "x-forwarded-port": "80"
  },
  "url": "https://postman-echo.com/get?foo=foo-value&bar=bar-value"
}

Notice that the headers section now contains two new attributes with the expected values.

In this guide we used extractions to add new headers, but you can use the extractions you define in any template.

Cleanup

To cleanup the resources created in this tutorial you can run the following commands:

kubectl delete virtualservice -n gloo-system extract-query-params
kubectl delete upstream -n gloo-system postman-echo