This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Cloud Gateway 4.2.0!

Developer Guide

These are basic guides to writing some custom components of the gateway.

Writing Custom Route Predicate Factories

In order to write a Route Predicate you will need to implement RoutePredicateFactory as a bean. There is an abstract class called AbstractRoutePredicateFactory which you can extend.

MyRoutePredicateFactory.java
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {

    public MyRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }

    public static class Config {
        //Put the configuration properties for your filter here
    }

}

Writing Custom GatewayFilter Factories

To write a GatewayFilter, you must implement GatewayFilterFactory as a bean. You can extend an abstract class called AbstractGatewayFilterFactory. The following examples show how to do so:

Example 1. PreGatewayFilterFactory.java
@Component
public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {

	public PreGatewayFilterFactory() {
		super(Config.class);
	}

	@Override
	public GatewayFilter apply(Config config) {
		// grab configuration from Config object
		return (exchange, chain) -> {
			//If you want to build a "pre" filter you need to manipulate the
			//request before calling chain.filter
			ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
			//use builder to manipulate the request
			return chain.filter(exchange.mutate().request(builder.build()).build());
		};
	}

	public static class Config {
		//Put the configuration properties for your filter here
	}

}
PostGatewayFilterFactory.java
@Component
public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {

	public PostGatewayFilterFactory() {
		super(Config.class);
	}

	@Override
	public GatewayFilter apply(Config config) {
		// grab configuration from Config object
		return (exchange, chain) -> {
			return chain.filter(exchange).then(Mono.fromRunnable(() -> {
				ServerHttpResponse response = exchange.getResponse();
				//Manipulate the response in some way
			}));
		};
	}

	public static class Config {
		//Put the configuration properties for your filter here
	}

}

Naming Custom Filters And References In Configuration

Custom filters class names should end in GatewayFilterFactory.

For example, to reference a filter named Something in configuration files, the filter must be in a class named SomethingGatewayFilterFactory.

It is possible to create a gateway filter named without the GatewayFilterFactory suffix, such as class AnotherThing. This filter could be referenced as AnotherThing in configuration files. This is not a supported naming convention and this syntax may be removed in future releases. Please update the filter name to be compliant.

Writing Custom Global Filters

To write a custom global filter, you must implement GlobalFilter interface as a bean. This applies the filter to all requests.

The following examples show how to set up global pre- and post-filters, respectively:

@Bean
public GlobalFilter customGlobalFilter() {
    return (exchange, chain) -> exchange.getPrincipal()
        .map(Principal::getName)
        .defaultIfEmpty("Default User")
        .map(userName -> {
          //adds header to proxied request
          exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
          return exchange;
        })
        .flatMap(chain::filter);
}

@Bean
public GlobalFilter customGlobalPostFilter() {
    return (exchange, chain) -> chain.filter(exchange)
        .then(Mono.just(exchange))
        .map(serverWebExchange -> {
          //adds header to response
          serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
              HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
          return serverWebExchange;
        })
        .then();
}