Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Overview
In this article, weβll explore the communication between a front-end application and a REST API that are deployed separately.
The goal is to work around CORS and the Same Origin Policy restriction of the browser and allow the UI to call the API even though they donβt share the same origin.
Weβll basically create two separate applications β a UI application and a simple REST API, and weβll use the Zuul proxy in the UI application to proxy calls to the REST API.
Zuul is a JVM based router and server side load balancer by Netflix. And Spring Cloud has a nice integration with an embedded Zuul proxy β which is what weβll use here.
Further reading:
An Example of Load Balancing with Zuul and Eureka
Setting Up Swagger 2 with a Spring REST API Using Springfox
Introduction to Spring REST Docs
2. Maven Configuration
First, we need to add a dependency to the zuul support from Spring Cloud to our UI applicationβs pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
The latest version can be found here.
3. Zuul Properties
Next β we need to configure Zuul, and since weβre using Spring Boot, weβre going to do that in the application.yml:
zuul:
routes:
foos:
path: /foos/**
url: http://localhost:8081/spring-zuul-foos-resource/foos
Note that:
- We are proxying to our resource server Foos.
- All requests from the UI that starts with β/foos/β will be routed to our Foos Resource server at http://loclahost:8081/spring-zuul-foos-resource/foos/
4. The API
Our API application is a simple Spring Boot app.
Within this article, weβre going to consider the API deployed in a server running on port 8081.
Letβs first define the basic DTO for the Resource weβre going to be using:
public class Foo {
private long id;
private String name;
// standard getters and setters
}
And a simple controller:
@RestController
public class FooController {
@GetMapping("/foos/{id}")
public Foo findById(
@PathVariable long id, HttpServletRequest req, HttpServletResponse res) {
return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4));
}
}
5. The UI Application
Our UI application is also a simple Spring Boot application.
Within this article, weβre going to consider the API deployed in a server running on port 8080.
Letβs start with the main index.html β using a bit of 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 most important aspect here is how weβre accessing the API using relative URLs!
Keep in mind that the API application isnβt deployed on the same server as the UI application, so relative URLs shouldnβt work, and wonβt work without the proxy.
With the proxy, however, weβre accessing the Foo resources through the Zuul proxy, which is of course configured to route these requests to wherever the API is actually deployed.
And finally, the actually Boot enabled application:
@EnableZuulProxy
@SpringBootApplication
public class UiApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(UiApplication.class, args);
}
}
Beyond the simple Boot annotation, notice that weβre using the enable-style of annotation for the Zuul proxy as well, which is pretty cool, clean and concise.
6. Test the Routing
Now β letβs test our UI application β as follows:
@Test
public void whenSendRequestToFooResource_thenOK() {
Response response = RestAssured.get("http://localhost:8080/foos/1");
assertEquals(200, response.getStatusCode());
}
7. A Custom Zuul Filter
There are multiple Zuul filters available, and we can also create our own custom one:
@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;
}
// ...
}
This simple filter just adds a header called βTestβ to the request β but of course, we can get as complex as we need to here augment our requests.
8. Test Custom Zuul Filter
Finally, letβs test make sure our custom filter is working β first we will modify our FooController at Foos resource server:
@RestController
public class FooController {
@GetMapping("/foos/{id}")
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));
}
}
Now β letβs test it out:
@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
In this write-up, we focused on using Zuul to route requests from a UI application to a REST API. We successfully worked around CORS and the same-origin policy and we also managed to customize and augment the HTTP request in transit.
