Transformations
Overview¶
Transformations allow you to dynamically modify requests and responses. That includes headers, query string parameters and body.
Depending on your vision and the specifics of your API products, you might use response/request transformations to:
- restrict the data returned to customers subscribed to a free product
- enforce a query string parameter to always have a certain value
- remove some elements from response body
- use Nadles Products as feature toggle
- and many more things
Example use case #1 — Truncate returned content
Say, you provide an API endpoint that returns the content of a news article. E.g.,
{
"id": "b6355c53-44a3-464b-bc9e-759749cdb3ec",
"title": "The title",
"content": "Some long article body"
}
For your "Free" product, you'd like to return only the first 120 characters of article body.
Nadles can do that for you, just create a product named "Free" and add a response transformation to truncate the article text.
Example use case #2 — Enforce query parameter value
If you have an endpoint that accepts a format
parameter, e.g. /articles/?format=<yaml|json|xml>
,
you might want to restrict the format for cheaper products to always be json
.
Add a request transformation to replace the query string parameter format
with json
— and all customers subscribed to this product will be unable to specify any value for the format
parameter other than json
.
This section describes product-scoped transformations. If a transformation is defined on a product level, it is only applied for the customers subscribed to this product.
Tip
Read about API-scoped transformations.
Transformations defined on an API level are always applied first.
How it works¶
graph TD
input[\"GET /endpoint1"/]
apply_api_req_tfs[Apply API-level request transformations]
apply_product_req_tfs[Apply product-level request transformations]
proxy_and_wait(("Proxy modified request
and wait for response"))
apply_api_resp_tfs[Apply API-level response transformations]
apply_product_resp_tfs[Apply product-level response transformations]
send_response[/Send modified response to the user\]
input --> apply_api_req_tfs
apply_api_req_tfs --> apply_product_req_tfs
apply_product_req_tfs --> proxy_and_wait
proxy_and_wait --> apply_api_resp_tfs
apply_api_resp_tfs --> apply_product_resp_tfs
apply_product_resp_tfs --> send_response
Transformation targets¶
Header¶
The transformation will add/replace/remove headers in a request or response.
Header names are case-insensitive.
Add¶
Adds a new header, even if there is already one with the same name.
Example
Original request:
Transformation:
Transformed request:
Replace¶
Replaces header(s) with a new value. If there are several headers with the given name, they're removed and replaced with the new value.
Example
Original request:
Transformation:
Transformed request:
Remove¶
Removes all headers with the given name.
Example
Original request:
Transformation:
Transformed request:
Query string parameter¶
The transformation will add/replace/remove query string parameters in a request.
Query string parameter names are case-sensitive.
Add¶
Adds a new query string parameter, even if there is already one or more with the same name.
Example
Original request:
Transformation:
Transformed request:
Replace¶
Replaces query string parameter(s) with a new value. If there are several query string parameters with the given name, they're removed and replaced with the new value.
Example
Original request:
Transformation:
Transformed request:
Remove¶
Removes all query string parameters with the given name.
Example
Original request:
Transformation:
Transformed request:
Body¶
The transformation will add/replace/remove request/response body.
Add¶
Adds a new body. If a request or response already has a body, it's left unchanged.
Example
Original request:
Transformation:
Transformed request:
Replace¶
Replaces the body with a new value. If there is no body yet, it's added.
Example
Original request:
Transformation:
Transformed request:
Remove¶
Removes the body.
Example
Original request:
Transformation:
Transformed request:
Expressions¶
JavaScript¶
You can use JavaScript expressions in your transformations to make them even more dynamic.
Expressions must evaluate to a new string value for the header/query string parameter/body.
Examples¶
Example — News API
Say, you provide an API endpoint that returns contents of a news article. E.g.,
{
"id": "b6355c53-44a3-464b-bc9e-759749cdb3ec",
"title": "The title",
"content": "Some long article body"
}
For your "Free" product, you'd like to return only the first 120 characters of article body.
With the following transformation added to the "Free" product, you configure Nadles API Gateway to do that:
Note that the expression evaluation result is used as the new value for the response body.
Note
If the original request or response body was compressed using GZip, Deflate or Brotli encoding, Nadles will compress the replaced body as well.
Expression variables¶
There are several variables you can use in your expressions.
Path parameters¶
path.params.*
— placeholder values specified in the endpoint URL.
Note
Placeholder names are case-sensitive.
Example
If an endpoint URL is /resource/{resourceId}
and the HTTP request URL is /resource/801d49c2-ca05-42b1-97af-baf0ddf36ba3
,
then there will be a variable path.params.resourceId
with value "801d49c2-ca05-42b1-97af-baf0ddf36ba3"
.
Client IP address¶
request.remote_addr
— Client IP address.
Request headers¶
request.headers['header-name']
— Request header values.
Warning
Header names are lower-case.
Request query string parameters¶
request.query['query_string_parameter_name']
— Request query string parameters.
Warning
Query string parameter names are case-sensitive.
Example¶
Request body¶
request.body
— Request body.
Example¶
Warning
Response variables are only available in response transformations.
Response status code¶
response.statusCode
— HTTP status code of the response from the upstream.
Example¶
Response headers¶
response.headers['header-name']
— Response header values.
Warning
Header names are lower-cased.
Example¶
Response body¶
response.body
— Raw response body.
Example¶
jq¶
You can also use jq expressions for transformations.
jq is like sed for JSON data - you can use it to slice and filter and map and transform JSON with the same ease that sed, awk, grep and friends let you play with text.
Unlike JavaScript expressions, the result of jq transformation does not necessarily have to be a string. If the expression result is not a string, it's encoded as JSON.
Examples¶
Example — News API
Say, you provide an API endpoint that returns contents of a news article. E.g.,
{
"id": "b6355c53-44a3-464b-bc9e-759749cdb3ec",
"title": "The title",
"content": "Some long article body"
}
For your "Free" product, you'd like to return only the first 120 characters of article body.
The following jq expression will do the job:
Note that the expression evaluation result is used as the new value for the response body.
Expression input¶
The followind is passed as input (.
) to each expression:
Input for request transformation expressions
{
"path": {
"params": { // path parameters, e.g. /endpoint/{path_param_1}
"path_param_1": "path_param_value_1",
"path_param_2": "path_param_value_2"
}
},
"request": {
"remote_addr": "127.0.0.1", // client IP address
"headers": { // request headers
"request_header_name_1": "header_value_1",
"request_header_name_2": ["header_values_2", "header_values_2"]
},
"query": { // query string parameters
"query_string_param_1": "query_string_param_value_1"
},
"body": "request body content"
},
}
Input for response transformation expressions
{
"path": {
"params": { // path parameters, e.g. /endpoint/{path_param_1}
"path_param_1": "path_param_value_1",
"path_param_2": "path_param_value_2"
}
},
"request": {
"remote_addr": "127.0.0.1", // client IP address
"headers": { // request headers
"request_header_name_1": "header_value_1",
"request_header_name_2": ["header_values_2", "header_values_2"]
},
"query": { // query string parameters
"query_string_param_1": "query_string_param_value_1"
},
"body": "request body content"
},
"request_transformed": { // request object, after request transformations are applied
// ...
},
"response": {
"statusCode": 200,
"headers": {
"response_header_name_1": "header_value_1",
"response_header_name_2": ["header_values_2", "header_values_2"]
},
"body": "response body content"
}
}
Tips and tricks¶
Feature toggle¶
Since transformations are applied in the scope of a product, you can use them to notify your API backend, what features are enabled for the current user.
You can configure Nadles to add a header (for instance, X-Features-Enabled
) to each request, with different values for each product.
E.g.,
Free | Basic | Advanced | |
---|---|---|---|
X-Features-Enabled | (empty) | full_article_content | full_article_content,chatgpt_suggestions |
On the API backend side you can check the value of the header and enable or disable the respective features.