Skip to content

Commit

Permalink
feat(callout-http): Provide an option to terminate request process in…
Browse files Browse the repository at this point in the history
… case of an error during callout

Closes gravitee-io/issues#1904
  • Loading branch information
brasseld committed Feb 9, 2019
1 parent b805a46 commit 1ff8e16
Show file tree
Hide file tree
Showing 5 changed files with 257 additions and 30 deletions.
32 changes: 28 additions & 4 deletions README.adoc
Expand Up @@ -45,28 +45,52 @@ execution. If no variable has been configured the result of the callout will not

.^|url
^.^|X
|URL invoked by the HTTP client
|URL invoked by the HTTP client (support EL)
^.^|URL
^.^|-

.^|headers
^.^|X
|List of HTTP headers used to invoke the URL (support EL).
|List of HTTP headers used to invoke the URL (support EL)
^.^|HTTP Headers
^.^|-

.^|body
^.^|X
|The body content send when calling the URL (support EL).
|The body content send when calling the URL (support EL)
^.^|string
^.^|-

.^|variables
^.^|X
|The variables to set in the execution context when retrieving content of HTTP call (support EL).
|The variables to set in the execution context when retrieving content of HTTP call (support EL)
^.^|List of variables
^.^|-

.^|exitOnError
^.^|X
|Terminate the request if the error condition is true
^.^|boolean
^.^|false

.^|errorCondition
^.^|X
|The condition which will be verified to end the request (support EL)
^.^|string
^.^|{#calloutResponse.status >= 400 and #calloutResponse.status <= 599}

.^|errorStatusCode
^.^|X
|HTTP Status Code send to the consumer if the condition is true
^.^|int
^.^|500

.^|errorContent
^.^|X
|The body response of the error if the condition is true (support EL)
^.^|string
^.^|-

|===

[source, json]
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -34,7 +34,7 @@
</parent>

<properties>
<gravitee-gateway-api.version>1.12.0</gravitee-gateway-api.version>
<gravitee-gateway-api.version>1.13.0-SNAPSHOT</gravitee-gateway-api.version>
<gravitee-policy-api.version>1.3.0</gravitee-policy-api.version>
<gravitee-common.version>1.13.0</gravitee-common.version>
<junit.version>4.12</junit.version>
Expand Down
62 changes: 40 additions & 22 deletions src/main/java/io/gravitee/policy/callout/CalloutHttpPolicy.java
Expand Up @@ -18,6 +18,7 @@
import io.gravitee.gateway.api.ExecutionContext;
import io.gravitee.gateway.api.Request;
import io.gravitee.gateway.api.Response;
import io.gravitee.gateway.api.expression.TemplateEngine;
import io.gravitee.policy.api.PolicyChain;
import io.gravitee.policy.api.PolicyResult;
import io.gravitee.policy.api.annotations.OnRequest;
Expand Down Expand Up @@ -77,30 +78,47 @@ public void handle(HttpClientResponse httpResponse) {
httpResponse.bodyHandler(new Handler<Buffer>() {
@Override
public void handle(Buffer body) {
TemplateEngine tplEngine = context.getTemplateEngine();

// Put response ino template variable for EL
context.getTemplateEngine().getTemplateContext()
tplEngine.getTemplateContext()
.setVariable(TEMPLATE_VARIABLE, new CalloutResponse(httpResponse, body.toString()));

// Set context variables
configuration.getVariables().forEach(variable -> {
try {
String extValue = (variable.getValue() != null) ?
context.getTemplateEngine().convert(variable.getValue()) : null;

context.setAttribute(variable.getName(), extValue);
} catch (Exception ex) {
// Do nothing
ex.printStackTrace();
}
});

context.getTemplateEngine().getTemplateContext()
.setVariable(TEMPLATE_VARIABLE, null);

// Finally continue chaining
policyChain.doNext(request, response);

// Close HTTP client
httpClient.close();

// Process callout response
boolean exit = false;

if (configuration.isExitOnError()) {
exit = tplEngine.getValue(configuration.getErrorCondition(), Boolean.class);
}

if (! exit) {
// Set context variables
configuration.getVariables().forEach(variable -> {
try {
String extValue = (variable.getValue() != null) ?
tplEngine.getValue(variable.getValue(), String.class) : null;

context.setAttribute(variable.getName(), extValue);
} catch (Exception ex) {
// Do nothing
}
});

tplEngine.getTemplateContext()
.setVariable(TEMPLATE_VARIABLE, null);

// Finally continue chaining
policyChain.doNext(request, response);
} else {
policyChain.failWith(
PolicyResult
.failure(
configuration.getErrorStatusCode(),
tplEngine.getValue(configuration.getErrorContent(), String.class)));
}
}
});
}
Expand All @@ -121,13 +139,13 @@ public void handle(Buffer body) {
}
} catch (Exception ex) {
// Do nothing
ex.printStackTrace();
}
});
}

if (configuration.getBody() != null && !configuration.getBody().isEmpty()) {
String body = context.getTemplateEngine().convert(configuration.getBody());
String body = context.getTemplateEngine()
.getValue(configuration.getBody(), String.class);
httpRequest.headers().remove(HttpHeaders.TRANSFER_ENCODING);
httpRequest.putHeader(HttpHeaders.CONTENT_LENGTH, Integer.toString(body.length()));
httpRequest.end(Buffer.buffer(body));
Expand Down
Expand Up @@ -16,6 +16,7 @@
package io.gravitee.policy.callout.configuration;

import io.gravitee.common.http.HttpMethod;
import io.gravitee.common.http.HttpStatusCode;
import io.gravitee.policy.api.PolicyConfiguration;

import java.util.ArrayList;
Expand All @@ -37,6 +38,14 @@ public class CalloutHttpPolicyConfiguration implements PolicyConfiguration {

private List<Variable> variables = new ArrayList<>();

private boolean exitOnError;

private String errorCondition;

private int errorStatusCode = HttpStatusCode.INTERNAL_SERVER_ERROR_500;

private String errorContent;

public String getUrl() {
return url;
}
Expand Down Expand Up @@ -76,4 +85,36 @@ public List<Variable> getVariables() {
public void setVariables(List<Variable> variables) {
this.variables = variables;
}

public boolean isExitOnError() {
return exitOnError;
}

public void setExitOnError(boolean exitOnError) {
this.exitOnError = exitOnError;
}

public String getErrorCondition() {
return errorCondition;
}

public void setErrorCondition(String errorCondition) {
this.errorCondition = errorCondition;
}

public int getErrorStatusCode() {
return errorStatusCode;
}

public void setErrorStatusCode(int errorStatusCode) {
this.errorStatusCode = errorStatusCode;
}

public String getErrorContent() {
return errorContent;
}

public void setErrorContent(String errorContent) {
this.errorContent = errorContent;
}
}
150 changes: 147 additions & 3 deletions src/main/resources/schemas/schema-form.json
Expand Up @@ -40,8 +40,14 @@
"title": "Request body",
"type" : "string",
"x-schema-form": {
"type": "textarea",
"placeholder": "Put your request body here"
"type": "codemirror",
"codemirrorOptions": {
"placeholder": "Put request body here",
"lineWrapping": true,
"lineNumbers": true,
"allowDropFileTypes": true,
"autoCloseTags": true
}
}
},
"variables" : {
Expand All @@ -66,10 +72,148 @@
"name",
"value"
]
},
"exitOnError": {
"title": "Exit on error",
"description": "Terminate the request if the error condition is true",
"type" : "boolean",
"default": false
},
"errorCondition": {
"title": "Error condition",
"description": "The condition which will be verified to end the request (support EL).",
"default": "{#calloutResponse.status >= 400 and #calloutResponse.status <= 599}",
"type" : "string"
},
"errorStatusCode": {
"title": "Error status code",
"description": "HTTP Status Code send to the consumer if the condition is true",
"type" : "string",
"default": "500",
"enum": [
"100",
"101",
"102",
"200",
"201",
"202",
"203",
"204",
"205",
"206",
"207",
"300",
"301",
"302",
"302",
"303",
"304",
"305",
"307",
"400",
"401",
"402",
"403",
"404",
"405",
"406",
"407",
"408",
"409",
"410",
"411",
"412",
"413",
"414",
"415",
"416",
"417",
"422",
"423",
"424",
"429",
"500",
"501",
"502",
"503",
"504",
"505",
"507"
],
"x-schema-form": {
"type": "select",
"titleMap": {
"100": "100 - CONTINUE",
"101": "101 - SWITCHING_PROTOCOLS",
"102": "102 - PROCESSING",
"200": "200 - OK",
"201": "201 - CREATED",
"202": "202 - ACCEPTED",
"203": "203 - NON_AUTHORITATIVE_INFORMATION",
"204": "204 - NO_CONTENT",
"205": "205 - RESET_CONTENT",
"206": "206 - PARTIAL_CONTENT",
"207": "207 - MULTI_STATUS",
"300": "300 - MULTIPLE_CHOICES",
"301": "301 - MOVED_PERMANENTLY",
"302": "302 - MOVED_TEMPORARILY",
"302": "302 - FOUND",
"303": "303 - SEE_OTHER",
"304": "304 - NOT_MODIFIED",
"305": "305 - USE_PROXY",
"307": "307 - TEMPORARY_REDIRECT",
"400": "400 - BAD_REQUEST",
"401": "401 - UNAUTHORIZED",
"402": "402 - PAYMENT_REQUIRED",
"403": "403 - FORBIDDEN",
"404": "404 - NOT_FOUND",
"405": "405 - METHOD_NOT_ALLOWED",
"406": "406 - NOT_ACCEPTABLE",
"407": "407 - PROXY_AUTHENTICATION_REQUIRED",
"408": "408 - REQUEST_TIMEOUT",
"409": "409 - CONFLICT",
"410": "410 - GONE",
"411": "411 - LENGTH_REQUIRED",
"412": "412 - PRECONDITION_FAILED",
"413": "413 - REQUEST_ENTITY_TOO_LARGE",
"414": "414 - REQUEST_URI_TOO_LONG",
"415": "415 - UNSUPPORTED_MEDIA_TYPE",
"416": "416 - REQUESTED_RANGE_NOT_SATISFIABLE",
"417": "417 - EXPECTATION_FAILED",
"422": "422 - UNPROCESSABLE_ENTITY",
"423": "423 - LOCKED",
"424": "424 - FAILED_DEPENDENCY",
"429": "429 - TOO_MANY_REQUESTS",
"500": "500 - INTERNAL_SERVER_ERROR",
"501": "501 - NOT_IMPLEMENTED",
"502": "502 - BAD_GATEWAY",
"503": "503 - SERVICE_UNAVAILABLE",
"504": "504 - GATEWAY_TIMEOUT",
"505": "505 - HTTP_VERSION_NOT_SUPPORTED",
"507": "507 - INSUFFICIENT_STORAGE"
}
}
},
"errorContent": {
"title": "Error response body",
"description": "The body response of the error if the condition is true (support EL)",
"type": "string",
"x-schema-form": {
"type": "codemirror",
"codemirrorOptions": {
"placeholder": "Put response body here",
"lineWrapping": true,
"lineNumbers": true,
"allowDropFileTypes": true,
"autoCloseTags": true,
"mode": "javascript"
}
}
}
},"required": [
"url",
"method",
"variables"
"variables",
"exitOnError"
]
}

0 comments on commit 1ff8e16

Please sign in to comment.