Spring REST with Zuul Proxy: A Step-by-Step Tutorial
This tutorial demonstrates how to use Spring Cloud's Zuul proxy to route requests from a separate UI application to a REST API, covering Maven setup, Zuul configuration, API and UI code, custom filters, and testing, while addressing CORS and same‑origin restrictions.
1. Overview
This article explores communication between a frontend UI application and a separately deployed REST API, aiming to solve CORS and same‑origin policy limitations so that the UI can call the API even when they are not on the same origin.
Two independent applications are created—a UI app and a simple REST API—using a Zuul proxy in the UI to forward API calls.
Zuul is a JVM‑based router and load balancer from Netflix that integrates smoothly with Spring Cloud.
2. Maven Configuration
Add Spring Cloud Zuul support to the UI project's pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.0.4.RELEASE</version>
</dependency>3. Zuul Properties
Configure Zuul routes in application.yml (Spring Boot):
zuul:
routes:
foos:
path: /foos/**
url: http://localhost:8081/spring-zuul-foos-resource/foosAll UI requests starting with /foos/ will be routed to the Foos resource server.
4. API
The API is a simple Spring Boot application running on port 8081.
Define a DTO for the resource:
public class Foo {
private long id;
private String name;
// standard getters and setters
}And a basic controller:
@Controller
public class FooController {
@RequestMapping(method = RequestMethod.GET, value = "/foos/{id}")
@ResponseBody
public Foo findById(@PathVariable long id, HttpServletRequest req, HttpServletResponse res) {
return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4));
}
}5. UI Application
The UI is also a Spring Boot app, deployed on port 8080, and starts with a simple index.html that uses AngularJS:
<html>
<body ng-app="myApp" ng-controller="mainCtrl">
<script src="angular.min.js"></script>
<script src="angular-resource.min.js"></script>
<script>
var app = angular.module('myApp', ["ngResource"]);
app.controller('mainCtrl', function($scope,$resource,$http) {
$scope.foo = {id:0 , name:"sample foo"};
$scope.foos = $resource("/foos/:fooId",{fooId:'@id'});
$scope.getFoo = function(){
$scope.foo = $scope.foos.get({fooId:$scope.foo.id});
}
});
</script>
<div>
<h1>Foo Details</h1>
<span>{{foo.id}}</span>
<span>{{foo.name}}</span>
<a href="#" ng-click="getFoo()">New Foo</a>
</div>
</body>
</html>The crucial point is that the UI must use relative URLs to reach the API; without a proxy, the calls would fail because the API is on a different server.
With Zuul enabled, the UI can access the Foo resource through the proxy, which forwards the request to the actual API location.
Enable the proxy with annotations:
@EnableZuulProxy
@SpringBootApplication
public class UiApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
}6. Test Routing
Verify that the UI can successfully call the API through Zuul:
@Test
public void whenSendRequestToFooResource_thenOK() {
Response response = RestAssured.get("http://localhost:8080/foos/1");
assertEquals(200, response.getStatusCode());
}7. Custom Zuul Filter
Create a custom filter to manipulate requests, for example adding a header named Test:
@Component
public class CustomZuulFilter extends ZuulFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader("Test", "TestSample");
return null;
}
@Override
public boolean shouldFilter() {
return true;
}
// ... other methods
}8. Test Custom Zuul Filter
Modify the FooController to echo the header and test that the filter works:
@Controller
public class FooController {
@GetMapping("/foos/{id}")
@ResponseBody
public Foo findById(@PathVariable long id, HttpServletRequest req, HttpServletResponse res) {
if (req.getHeader("Test") != null) {
res.addHeader("Test", req.getHeader("Test"));
}
return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4));
}
} @Test
public void whenSendRequest_thenHeaderAdded() {
Response response = RestAssured.get("http://localhost:8080/foos/1");
assertEquals(200, response.getStatusCode());
assertEquals("TestSample", response.getHeader("Test"));
}9. Conclusion
The tutorial shows how to use Zuul to route UI requests to a REST API, solving CORS and same‑origin issues, and demonstrates how to customize and extend HTTP requests with custom filters. The full Maven project is available on GitHub.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
