visit
All API Gateways that I know about provide a Docker image. For example, Apache APISIX provide three flavours: Debian, CentOS, and recently, Red Hat. At this point, you can start deploying the images in your containerized architecture.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>4.0.6</version>
</dependency>
In particular, you can create an Upstream
abstraction and share it across different routes. Likewise, Plugin Config
allows you to create a reusable combination of plugins.
The APISIX model is richer, with abstractions and the possibility of reuse.
Apache APISIX has two deployment modes (actually three, but let’s not get into details): traditional and standalone.
In traditional mode, APISIX stores its configuration in . APISIX offers a rich API to access and update the configuration, the . In standalone mode, the configuration is just plain YAML. It’s the approach for GitOps practitioners: you’d store your configuration in a Git repo, watch it via your favorite tool (e.g., Argo CD or Tekton), and the latter would propagate the changes to APISIX nodes upon changes. APISIX reloads its configuration every second or so.
upstreams:
- id: 1
nodes:
"catalog:8080": 1
- id: 2
nodes:
"pricing:8080": 1
routes:
- uri: /v1/products*
upstream_id: 1
plugins:
proxy-rewrite:
regex_uri: ["/v1(.*)", "$1"]
- uri: /prices*
upstream_id: 2
plugins:
referer-restriction:
whitelist:
- catalog.me
global_rules:
plugins:
prometheus:
prefer_name: true
Spring Cloud Gateway supports all configuration options of regular Spring projects, and they are . However, "flat" configurations, such as .properties
file(s) and environment variables, are error-prone:
spring.cloud.gateway.routes[0].id=products
spring.cloud.gateway.routes[0].uri=//catalog:8080
spring.cloud.gateway.routes[0].predicates[0]=Path=/v1/products*
spring.cloud.gateway.routes[1].id=pricing
spring.cloud.gateway.routes[1].uri=//pricing:8080
spring.cloud.gateway.routes[1].predicates[0]=Path=/prices*
spring.cloud.gateway.routes[1].predicates[1]=Header=Referer, //catalog.me
spring.cloud.gateway.routes:
- id: products
uri: //catalog:8080
predicates:
- Path=/v1/products*
filters:
- StripPrefix=1
- id: pricing
uri: //pricing:8080
predicates:
- Path=/prices*
- Header=Referer, //catalog.me
As for Apache APISIX, you can also create via the /actuator
endpoint. However, the API doesn’t offer a PATCH
method: you need to update the whole route in case of updates.
Apache APISIX implements features with plugins, while Spring Cloud Gateway implements them with filters. While an exhaustive, detailed feature-by-feature comparison is beyond the scope of a single blog post, we can still get a good overview.
Feature | Spring Gateway | Apache APISIX |
---|---|---|
Request headers manipulation |
|
|
Path manipulation |
|
|
Response headers manipulation |
|
|
Redirection |
|
|
JSON gRPC transcoding |
|
|
Body manipulation |
|
|
Resiliency |
|
|
Resiliency |
|
|
Resiliency | - |
|
Caching |
|
|
Some plugins are Spring-specific, e.g., SaveSession
- APISIX has no such integration. Conversely, APISIX provides many plugins for authentication with different third-party services, e.g., KeyCloak, OpenId Connect, etc. Spring Cloud Gateway achieves it via the Spring Security dependency, a whole subject.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.11.0</version>
</dependency>
zipkin
, skywalking
, and opentelemetry
prometheus
, node-status
, and datadog
I’ve slightly changed the implementation, though, to leverage the gateway. Instead of the catalog calling the pricing/stocks components, I call the gateway to forward the call. Additionally, I want to prevent external callers from accessing pricing and stocks: only the catalog should be allowed.
Prometheus scraps the metrics of the gateway. Apache APISIX offers a dedicated port and thread, so regular routing and observing are decoupled. You can also customize the path to the endpoint. Spring Cloud Gateway uses the same port but a specific path, /actuator
, which you can customize. You can also change the port of the whole actuator via the management.server.port
property.
docker compose up
curl localhost:8080/products
Spring Cloud Gateway stems from the Spring framework and the Spring Boot platform and essentially focuses on developers already familiar with Spring. If you’re in such a scenario, it’s easy to get into as one feels right at home, with a slight warning. For performance reasons, Spring Cloud Gateway implements non-blocking I/O with Spring WebFlux, which relies Project Reactor. It will be a challenging ride if you need to code non-trivial logic using code and you’re not familiar with Mono
and Flux
.
On the other side, while using it without prior knowledge of Spring internals is possible, it will be a massive step for non-Spring developers. It will be an even more gigantic step if they are not JVM developers and a complete leap of faith if they aren’t developers at all, i.e., Ops.
Thanks for his kind review. He also pointed out to me misconceptions I had about Spring Cloud Gateway. Muchas gracias amigo!
To go further:
Originally at on June 18th, 2023.