description |
---|
This page provides the technical details of the Javascript policy |
You can use this policy to run Javascript scripts at every stage of Gateway processing.
Functional and implementation information for the javascript
policy is organized into the following sections:
{% hint style="warning" %} This policy can be applied to v2 APIs and v4 HTTP proxy APIs. It cannot be applied to v4 message APIs or v4 TCP proxy APIs. {% endhint %}
{% tabs %} {% tab title="HTTP proxy API example" %} Example 1
This script stops the processing if the request contains a certain header:
if (request.headers.containsKey('X-Gravitee-Break')) {
result.key = 'RESPONSE_TEMPLATE_KEY';
result.state = State.FAILURE;
result.code = 500
result.error = 'Stop request processing due to X-Gravitee-Break header'
} else {
request.headers.set('X-JavaScript-Policy', 'ok');
}
To customize the error sent by the policy:
result.key = 'RESPONSE_TEMPLATE_KEY';
result.state = State.FAILURE;
result.code = 400
result.error = '{"error":"My specific error message","code":"MY_ERROR_CODE"}'
result.contentType = 'application/json'
Example 2
The following shows how to use the javascript
policy to transform JSON content.
Assuming the request body below (input body content):
[
{
"age": 32,
"firstname": "John",
"lastname": "Doe"
}
]
You can run the following JavaScript script:
var content = JSON.parse(response.content);
content[0].firstname = 'Hacked ' + content[0].firstname;
content[0].country = 'US';
JSON.stringify(content);
And the request body being passed to the API will be (output body content):
[
{
"age": 32,
"firstname": "Hacked John",
"lastname": "Doe",
"country": "US"
}
]
Example 3
Assume that you sent the request body modified above to an echo API. You can run the following:
var content = JSON.parse(response.content);
content[0].firstname = content[0].firstname.substring(7);
delete content[0].country;
JSON.stringify(content);
And the response message will be:
[
{
"age": 32,
"firstname": "John",
"lastname": "Doe"
}
]
{% endtab %} {% endtabs %}
"javascript": {
"onRequestScript": "response.headers.remove('X-Powered-By');",
"onResponseScript": "response.headers.set('X-Gravitee-Gateway-Version', '0.14.0');",
"onRequestContentScript": "" // Not executed if empty
"onResponseContentScript": "" // Not executed if empty
}
The phases checked below are supported by the javascript
policy:
v2 Phases | Compatible? | v4 Phases | Compatible? |
---|---|---|---|
onRequest | true | onRequest | true |
onResponse | true | onResponse | true |
onRequestContent | true | onMessageRequest | false |
onResponseContent | true | onMessageResponse | false |
Some variables are automatically bound to the JavaScript script to allow users to use them and define the policy behavior:
Name | Description |
---|---|
request | Inbound HTTP request |
response | Outbound HTTP response |
context | PolicyContext used to access external components such as services and resources |
result | JavaScript script result |
Request or response processing can be interrupted by setting the result state to FAILURE
. By default, it will throw a 500 - internal server error
, but you can override this behavior with the following properties:
code
: An HTTP status codeerror
: The error messagekey
: The key of a response template
In the onRequestContent
phase you have access to the content
object, also known as the request body. You can modify this object.
In the onResponseContent
phase you have access to the content
object, also known as the response message. You can modify this object.
For example, you can transform request or response body content by applying a JavaScript script on the OnRequestContent
phase or the OnResponseContent
phase.
{% hint style="warning" %}
When working with scripts on OnRequestContent
or OnResponseContent
phase, the last instruction of the script must be the new body content that would be returned by the policy.
{% endhint %}
Both dictionaries (defined at the environment level) and properties (defined at the API level) can be accessed from the JavaScript script using:
context.dictionaries()
for dictionariescontext.properties()
for properties
Here is an example of how to set a request header based on a property:
request.headers.set('X-JavaScript-Policy', context.properties()['KEY_OF_MY_PROPERTY']);
The javascript
policy can be used to configure the request
, response
, and metrics
objects:
{% tabs %} {% tab title="onRequest" %}
Object | Property | Type | Description |
---|---|---|---|
request | id | string | - |
request | transactionId | string | - |
request | uri | string | - |
request | path | string | - |
request | pathInfo | string | - |
request | contextPath | string | - |
request | parameters | multivalue map | - |
request | pathParameters | multivalue map | - |
request | headers | iterable map <string, string> | - |
request | method | enum | - |
request | version | enum | - |
request | timestamp | long | - |
request | remoteAddress | string | - |
request | localAddress | string | - |
request | scheme | string | - |
request | sslSession | javax.net.ssl.SSLSession | - |
request | metrics | object | |
{% endtab %} |
{% tab title="onResponse" %}
In the onResponse
phase, you have access to the request
, the response
and the context
object.
Object | Property | Type | Description |
---|---|---|---|
response | status | int | - |
response | reason | String | - |
response | headers | iterable map <string, string> | - |
{% endtab %} |
{% tab title="Metrics" %}
It is highly advisable to use the Metrics Reporter in order to manage the metrics. However, the request
object does contain a metrics
object.
Note that the metrics
object changes in the different processing phases. Some properties may not make sense in certain phases.
Object | Property | Type | Description |
---|---|---|---|
metrics | api | String | ID of the API |
metrics | apiResponseTimeMs | long | Response time spend to call the backend upstream |
metrics | application | String | ID of the consuming application |
metrics | endpoint | String | - |
metrics | errorKey | String | Key of the error if the policy chain is failing |
metrics | host | String | Host header value |
metrics | httpMethod | enum | - |
metrics | localAddress | String | - |
metrics | log | object | - |
metrics | mappedPath | String | - |
metrics | message | String | - |
metrics | path | String | - |
metrics | plan | String | ID of the plan |
metrics | proxyLatencyMs | long | Latency of the gateway to apply policies |
metrics | proxyResponseTimeMs | long | Global response time to process and respond to the consumer |
metrics | remoteAddress | String | - |
metrics | requestContentLength | long | - |
metrics | requestId | String | - |
metrics | responseContentLength | long | - |
metrics | securityToken | String | - |
metrics | securityType | enum | - |
metrics | status | int | - |
metrics | subscription | String | ID of the subscription |
metrics | tenant | String | gateway tenant value |
metrics | transactionId | String | - |
metrics | uri | String | - |
metrics | user | String | End-user doing the call (in case of OAuth2 / JWT / Basic Auth) |
metrics | userAgent | String | Value of the user-agent header |
metrics | zone | String | Gateway zone |
HTTP status code | Message |
---|---|
500 | The JavaScript script cannot be parsed/compiled or executed (mainly due to a syntax error) |
{% @github-files/github-code-block url="https://github.com/gravitee-io/gravitee-policy-javascript/blob/master/CHANGELOG.md" %}