/*
 * Copyright 2018 Red Hat, Inc.
 *
 * Red Hat licenses this file to you under the Apache License, version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package io.vertx.ext.web.client.predicate;

import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.http.HttpHeaders;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.impl.predicate.ResponsePredicateImpl;

import java.util.Collections;
import java.util.List;
import java.util.function.Function;

A predicate on HttpResponse.

By default, a Vert.x Web Client request ends with an error only if something wrong happens at the network level. In other words, a 404 Not Found response, or a response with the wrong content type, are NOT considered as failures.

Response predicates can fail a request when the response does not match some criteria.

Custom predicate instances can be used with HttpRequest.expect(Function).

As a convenience, a few predicates for common uses cases are predefined. For example:

  • SC_SUCCESS to verify that the response has a 2xx code, or
  • JSON to verify that the response body contains JSON data.
  • ...
Predefined predicates use the default error converter (discarding the body).

However, you can create a new ResponsePredicate instance from an existing one using create(Function<HttpResponse<Void>,ResponsePredicateResult>) or create(Function<HttpResponse<Void>,ResponsePredicateResult>, ErrorConverter) when the body is required to build the validation failure.

/** * A predicate on {@link HttpResponse}. * <p> * By default, a Vert.x Web Client request ends with an error only if something wrong happens at the network level. * In other words, a {@code 404 Not Found} response, or a response with the wrong content type, are <em>NOT</em> considered as failures. * <p> * {@link ResponsePredicate Response predicates} can fail a request when the response does not match some criteria. * <p> * Custom predicate instances can be used with {@link HttpRequest#expect(Function)}. * <p> * As a convenience, a few predicates for common uses cases are predefined. For example: * <ul> * <li>{@link #SC_SUCCESS} to verify that the response has a {@code 2xx} code, or</li> * <li>{@link #JSON} to verify that the response body contains JSON data.</li> * <li>...</li> * </ul> * Predefined predicates use the default error converter (discarding the body). * <p> * However, you can create a new {@link ResponsePredicate} instance from an existing one using {@link #create(Function)} or * {@link #create(Function, ErrorConverter)} when the body is required to build the validation failure. */
@VertxGen public interface ResponsePredicate extends Function<HttpResponse<Void>, ResponsePredicateResult> {
Any 1XX informational response
/** * Any 1XX informational response */
ResponsePredicate SC_INFORMATIONAL_RESPONSE = status(100, 200);
100 Continue
/** * 100 Continue */
ResponsePredicate SC_CONTINUE = status(100);
101 Switching Protocols
/** * 101 Switching Protocols */
ResponsePredicate SC_SWITCHING_PROTOCOLS = status(101);
102 Processing (WebDAV, RFC2518)
/** * 102 Processing (WebDAV, RFC2518) */
ResponsePredicate SC_PROCESSING = status(102);
103 Early Hints
/** * 103 Early Hints */
ResponsePredicate SC_EARLY_HINTS = status(103);
Any 2XX success
/** * Any 2XX success */
ResponsePredicate SC_SUCCESS = status(200, 300);
200 OK
/** * 200 OK */
ResponsePredicate SC_OK = status(200);
201 Created
/** * 201 Created */
ResponsePredicate SC_CREATED = status(201);
202 Accepted
/** * 202 Accepted */
ResponsePredicate SC_ACCEPTED = status(202);
203 Non-Authoritative Information (since HTTP/1.1)
/** * 203 Non-Authoritative Information (since HTTP/1.1) */
ResponsePredicate SC_NON_AUTHORITATIVE_INFORMATION = status(203);
204 No Content
/** * 204 No Content */
ResponsePredicate SC_NO_CONTENT = status(204);
205 Reset Content
/** * 205 Reset Content */
ResponsePredicate SC_RESET_CONTENT = status(205);
206 Partial Content
/** * 206 Partial Content */
ResponsePredicate SC_PARTIAL_CONTENT = status(206);
207 Multi-Status (WebDAV, RFC2518)
/** * 207 Multi-Status (WebDAV, RFC2518) */
ResponsePredicate SC_MULTI_STATUS = status(207);
Any 3XX redirection
/** * Any 3XX redirection */
ResponsePredicate SC_REDIRECTION = status(300, 400);
300 Multiple Choices
/** * 300 Multiple Choices */
ResponsePredicate SC_MULTIPLE_CHOICES = status(300);
301 Moved Permanently
/** * 301 Moved Permanently */
ResponsePredicate SC_MOVED_PERMANENTLY = status(301);
302 Found
/** * 302 Found */
ResponsePredicate SC_FOUND = status(302);
303 See Other (since HTTP/1.1)
/** * 303 See Other (since HTTP/1.1) */
ResponsePredicate SC_SEE_OTHER = status(303);
304 Not Modified
/** * 304 Not Modified */
ResponsePredicate SC_NOT_MODIFIED = status(304);
305 Use Proxy (since HTTP/1.1)
/** * 305 Use Proxy (since HTTP/1.1) */
ResponsePredicate SC_USE_PROXY = status(305);
307 Temporary Redirect (since HTTP/1.1)
/** * 307 Temporary Redirect (since HTTP/1.1) */
ResponsePredicate SC_TEMPORARY_REDIRECT = status(307);
308 Permanent Redirect (RFC7538)
/** * 308 Permanent Redirect (RFC7538) */
ResponsePredicate SC_PERMANENT_REDIRECT = status(308);
Any 4XX client error
/** * Any 4XX client error */
ResponsePredicate SC_CLIENT_ERRORS = status(400, 500);
400 Bad Request
/** * 400 Bad Request */
ResponsePredicate SC_BAD_REQUEST = status(400);
401 Unauthorized
/** * 401 Unauthorized */
ResponsePredicate SC_UNAUTHORIZED = status(401);
402 Payment Required
/** * 402 Payment Required */
ResponsePredicate SC_PAYMENT_REQUIRED = status(402);
403 Forbidden
/** * 403 Forbidden */
ResponsePredicate SC_FORBIDDEN = status(403);
404 Not Found
/** * 404 Not Found */
ResponsePredicate SC_NOT_FOUND = status(404);
405 Method Not Allowed
/** * 405 Method Not Allowed */
ResponsePredicate SC_METHOD_NOT_ALLOWED = status(405);
406 Not Acceptable
/** * 406 Not Acceptable */
ResponsePredicate SC_NOT_ACCEPTABLE = status(406);
407 Proxy Authentication Required
/** * 407 Proxy Authentication Required */
ResponsePredicate SC_PROXY_AUTHENTICATION_REQUIRED = status(407);
408 Request Timeout
/** * 408 Request Timeout */
ResponsePredicate SC_REQUEST_TIMEOUT = status(408);
409 Conflict
/** * 409 Conflict */
ResponsePredicate SC_CONFLICT = status(409);
410 Gone
/** * 410 Gone */
ResponsePredicate SC_GONE = status(410);
411 Length Required
/** * 411 Length Required */
ResponsePredicate SC_LENGTH_REQUIRED = status(411);
412 Precondition Failed
/** * 412 Precondition Failed */
ResponsePredicate SC_PRECONDITION_FAILED = status(412);
413 Request Entity Too Large
/** * 413 Request Entity Too Large */
ResponsePredicate SC_REQUEST_ENTITY_TOO_LARGE = status(413);
414 Request-URI Too Long
/** * 414 Request-URI Too Long */
ResponsePredicate SC_REQUEST_URI_TOO_LONG = status(414);
415 Unsupported Media Type
/** * 415 Unsupported Media Type */
ResponsePredicate SC_UNSUPPORTED_MEDIA_TYPE = status(415);
416 Requested Range Not Satisfiable
/** * 416 Requested Range Not Satisfiable */
ResponsePredicate SC_REQUESTED_RANGE_NOT_SATISFIABLE = status(416);
417 Expectation Failed
/** * 417 Expectation Failed */
ResponsePredicate SC_EXPECTATION_FAILED = status(417);
421 Misdirected Request
/** * 421 Misdirected Request */
ResponsePredicate SC_MISDIRECTED_REQUEST = status(421);
422 Unprocessable Entity (WebDAV, RFC4918)
/** * 422 Unprocessable Entity (WebDAV, RFC4918) */
ResponsePredicate SC_UNPROCESSABLE_ENTITY = status(422);
423 Locked (WebDAV, RFC4918)
/** * 423 Locked (WebDAV, RFC4918) */
ResponsePredicate SC_LOCKED = status(423);
424 Failed Dependency (WebDAV, RFC4918)
/** * 424 Failed Dependency (WebDAV, RFC4918) */
ResponsePredicate SC_FAILED_DEPENDENCY = status(424);
425 Unordered Collection (WebDAV, RFC3648)
/** * 425 Unordered Collection (WebDAV, RFC3648) */
ResponsePredicate SC_UNORDERED_COLLECTION = status(425);
426 Upgrade Required (RFC2817)
/** * 426 Upgrade Required (RFC2817) */
ResponsePredicate SC_UPGRADE_REQUIRED = status(426);
428 Precondition Required (RFC6585)
/** * 428 Precondition Required (RFC6585) */
ResponsePredicate SC_PRECONDITION_REQUIRED = status(428);
429 Too Many Requests (RFC6585)
/** * 429 Too Many Requests (RFC6585) */
ResponsePredicate SC_TOO_MANY_REQUESTS = status(429);
431 Request Header Fields Too Large (RFC6585)
/** * 431 Request Header Fields Too Large (RFC6585) */
ResponsePredicate SC_REQUEST_HEADER_FIELDS_TOO_LARGE = status(431);
Any 5XX server error
/** * Any 5XX server error */
ResponsePredicate SC_SERVER_ERRORS = status(500, 600);
500 Internal Server Error
/** * 500 Internal Server Error */
ResponsePredicate SC_INTERNAL_SERVER_ERROR = status(500);
501 Not Implemented
/** * 501 Not Implemented */
ResponsePredicate SC_NOT_IMPLEMENTED = status(501);
502 Bad Gateway
/** * 502 Bad Gateway */
ResponsePredicate SC_BAD_GATEWAY = status(502);
503 Service Unavailable
/** * 503 Service Unavailable */
ResponsePredicate SC_SERVICE_UNAVAILABLE = status(503);
504 Gateway Timeout
/** * 504 Gateway Timeout */
ResponsePredicate SC_GATEWAY_TIMEOUT = status(504);
505 HTTP Version Not Supported
/** * 505 HTTP Version Not Supported */
ResponsePredicate SC_HTTP_VERSION_NOT_SUPPORTED = status(505);
506 Variant Also Negotiates (RFC2295)
/** * 506 Variant Also Negotiates (RFC2295) */
ResponsePredicate SC_VARIANT_ALSO_NEGOTIATES = status(506);
507 Insufficient Storage (WebDAV, RFC4918)
/** * 507 Insufficient Storage (WebDAV, RFC4918) */
ResponsePredicate SC_INSUFFICIENT_STORAGE = status(507);
510 Not Extended (RFC2774)
/** * 510 Not Extended (RFC2774) */
ResponsePredicate SC_NOT_EXTENDED = status(510);
511 Network Authentication Required (RFC6585)
/** * 511 Network Authentication Required (RFC6585) */
ResponsePredicate SC_NETWORK_AUTHENTICATION_REQUIRED = status(511);
Creates a predicate asserting that the status response code is equal to statusCode.
Params:
  • statusCode – the expected status code
/** * Creates a predicate asserting that the status response code is equal to {@code statusCode}. * * @param statusCode the expected status code */
static ResponsePredicate status(int statusCode) { return status(statusCode, statusCode + 1); }
Creates a predicate asserting that the status response code is in the [min,max[ range.
Params:
  • min – the lower (inclusive) accepted status code
  • max – the highest (exclusive) accepted status code
/** * Creates a predicate asserting that the status response code is in the {@code [min,max[} range. * * @param min the lower (inclusive) accepted status code * @param max the highest (exclusive) accepted status code */
static ResponsePredicate status(int min, int max) { return response -> { int sc = response.statusCode(); if (sc >= min && sc < max) { return ResponsePredicateResult.success(); } if (max - min == 1) { return ResponsePredicateResult.failure("Response status code " + sc + " is not equal to " + min); } return ResponsePredicateResult.failure("Response status code " + sc + " is not between " + min + " and " + max); }; }
Creates a predicate validating the response content-type is application/json.
/** * Creates a predicate validating the response {@code content-type} is {@code application/json}. */
ResponsePredicate JSON = contentType("application/json");
Creates a predicate validating the response has a content-type header matching the mimeType.
Params:
  • mimeType – the mime type
/** * Creates a predicate validating the response has a {@code content-type} header matching the {@code mimeType}. * * @param mimeType the mime type */
static ResponsePredicate contentType(String mimeType) { return ResponsePredicate.contentType(Collections.singletonList(mimeType)); }
Creates a predicate validating the response has a content-type header matching one of the mimeTypes.
Params:
  • mimeTypes – the list of mime types
/** * Creates a predicate validating the response has a {@code content-type} header matching one of the {@code mimeTypes}. * * @param mimeTypes the list of mime types */
static ResponsePredicate contentType(List<String> mimeTypes) { return response -> { String contentType = response.headers().get(HttpHeaders.CONTENT_TYPE); if (contentType == null) { return ResponsePredicateResult.failure("Missing response content type"); } for (String mimeType : mimeTypes) { if (contentType.equalsIgnoreCase(mimeType)) { return ResponsePredicateResult.success(); } } StringBuilder sb = new StringBuilder("Expect content type ").append(contentType).append(" to be one of "); boolean first = true; for (String mimeType : mimeTypes) { if (!first) { sb.append(", "); } first = false; sb.append(mimeType); } return ResponsePredicateResult.failure(sb.toString()); }; }
Creates a new ResponsePredicate. The default error converter will be used (discarding the body).
Params:
  • test – the function to invoke when the response is received
/** * Creates a new {@link ResponsePredicate}. The default error converter will be used (discarding the body). * * @param test the function to invoke when the response is received */
static ResponsePredicate create(Function<HttpResponse<Void>, ResponsePredicateResult> test) { return test::apply; }
Creates a new ResponsePredicate, using a custom errorConverter.
Params:
  • test – the function to invoke when the response is received
  • errorConverter – converts the result of the test function to a Throwable
/** * Creates a new {@link ResponsePredicate}, using a custom {@code errorConverter}. * * @param test the function to invoke when the response is received * @param errorConverter converts the result of the {@code test} function to a {@link Throwable} */
static ResponsePredicate create(Function<HttpResponse<Void>, ResponsePredicateResult> test, ErrorConverter errorConverter) { return new ResponsePredicateImpl(test, errorConverter); }
Returns:the error converter currently used
/** * @return the error converter currently used */
default ErrorConverter errorConverter() { return ErrorConverter.DEFAULT_CONVERTER; } }