Open lesson "Creating REST-clients on Spring"
And again, good day! Very soon we will start training the next group “Developer on the Spring Framework” , in connection with which we conducted an open lesson, which has become a tradition on the eve of the launch. This webinar talked about developing REST clients using Spring, and also learned in detail about technologies such as Spring Cache, Spring Retry, and Hystrix.
Lecturer: Yuri Dvorzhetsky - a trainer at Luxoft Training Center, a leading developer, Candidate of Physical and Mathematical Sciences.
The webinar was visited by a completely different audience, assessing their knowledge of Spring within 0-6 points on a 10-point scale, but judging by the reviews, the open lesson seemed useful even to experienced users.
A few words about Spring 5
As you know, the Spring Framework is a versatile and quite popular framework for the Java platform. Spring consists of a mass of subprojects or modules that allows you to solve many problems. In fact, this is a large collection of frameworks in the framework, for example, just a few of them:
Spring replaces the programming of some tasks with configuration, however, configuration sometimes turns into just a nightmare. To quickly create production-grade applications, use Spring Boot . This is a special framework that contains a set of starters ('starter') that simplify the configuration of Spring frameworks and other technologies.
To show some features of the work of Spring, the theme of blocking sites is perfect, as it is now fashionable)). If you want to actively participate in the lesson and practice, it is recommended to download the repository with the server code offered by the teacher. Use the following command:
Next, just run, for example, like this:
The biggest achievement of Spring Boot is the ability to start the server by simply launching the Main class in IntelliJ IDEA.
The file BlockedSite.java contains our source code:
But the contents of the BlockedSitesController.java controller:
Also note the nested database in pom.xml:
Now, in a simple and straightforward way, we save two blocked sites (DemoServerApplication.java) to our database via the repository:
It remains to start the server using Spring Boot and open the corresponding URL on the local host
Well, it's time to write a client to this server. But before you go to this, you need to remember something.
Theoretical retreat
Let us list some HTTP methods (verbs):
It is impossible not to recall such an important property as idempotency . In simple terms, no matter how many times you use an operation, its result will be the same, as if you applied it only once. For example, you greeted the person in the morning, saying “Hello!” As a result, your friend goes into the “greeted” state :-). And if you say hello several times during the day, nothing will change, it will remain in the same state.
And now, let's think about which of the above HTTP methods are idempotent? Of course, it is implied that you observe semantics. If you do not know, then the teacher tells more about this, starting with the 26th minute of the video.
REST
In order to write a REST controller, you need to remember what REST is:
First, if we talk about interaction in the form of a client-server, then it needs to be built in the form of a request-response. Yes, the interaction is not always built that way, but now this interaction is extremely common, and for web applications, something else looks quite strange. And here, for example, web sockets is just not REST.
Secondly, the most important restriction in REST is the lack of client status on the server. It is assumed that the client server always sends all the necessary state with each request, that is, the state is saved on the client side, and there are no sessions on the server.
How to write a client on Spring
To continue work, consider and run the client (use the link to the repository):
This is a client and console application already written, not a web server.
See dependencies:
The client has the configuration:
1. RestTemplateConfig.java
2. CacheConfig.java
But the contents of the SiteServiceRest.java file:
Slightly summarize:
Colleagues, the webinar turned out to be very informative, therefore, in order not to miss anything, it’s better to watch it completely. You will try a real API "in combat conditions", add
And, as usual, we are waiting for your comments on the past open lesson!
Lecturer: Yuri Dvorzhetsky - a trainer at Luxoft Training Center, a leading developer, Candidate of Physical and Mathematical Sciences.
The webinar was visited by a completely different audience, assessing their knowledge of Spring within 0-6 points on a 10-point scale, but judging by the reviews, the open lesson seemed useful even to experienced users.
A few words about Spring 5
As you know, the Spring Framework is a versatile and quite popular framework for the Java platform. Spring consists of a mass of subprojects or modules that allows you to solve many problems. In fact, this is a large collection of frameworks in the framework, for example, just a few of them:
- Spring IoC + AOP = Context,
- Spring jdbc
- Spring ORM,
- Spring Data (this is a whole set of subprojects),
- Spring MVC, Spring WebFlux,
- Spring Security,
- Spring Cloud (it's an even bigger set of sub-projects),
- Spring Batch,
- Spring Boot.
Spring replaces the programming of some tasks with configuration, however, configuration sometimes turns into just a nightmare. To quickly create production-grade applications, use Spring Boot . This is a special framework that contains a set of starters ('starter') that simplify the configuration of Spring frameworks and other technologies.
To show some features of the work of Spring, the theme of blocking sites is perfect, as it is now fashionable)). If you want to actively participate in the lesson and practice, it is recommended to download the repository with the server code offered by the teacher. Use the following command:
git clone git@github.com:ydvorzhetskiy/sb-server.git
Next, just run, for example, like this:
mvnw spring-boot:run
The biggest achievement of Spring Boot is the ability to start the server by simply launching the Main class in IntelliJ IDEA.
The file BlockedSite.java contains our source code:
package ru.otus.demoserver.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public classBlockedSite{
@Id
@GeneratedValue
private int id;
private String url;
But the contents of the BlockedSitesController.java controller:
package ru.otus.demoserver.rest;
@RestController
public classBlockedSitesController{
private final Logger logger = LoggerFactory.getLogger(BlockedSitesController.class);
private final BlockedSitesRepository repository;
public BlockedSitesController(BlockedSitesRepository repository) {
this.repository = repository;
}
@GetMapping("/blocked-sites")
public List<BlockedSite> blockedSites() {
logger.info("Request has been performed");
return repository.findAll();
}
}
Also note the nested database in pom.xml:
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version><relativePath/><!-- lookup parent from repository --></parent><groupId>ru.otus</groupId><artifactId>demo-server</artifactId><version>0.0.1-SNAPSHOT</version><url>demo-server</url><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
Now, in a simple and straightforward way, we save two blocked sites (DemoServerApplication.java) to our database via the repository:
package ru.otus.demoserver;
@SpringBootApplication
public classDemoServerApplication{
public staticvoid main(String[] args) {
ApplicationContext ctx = SpringApplication.run(DemoServerApplication.class, args);
BlockedSitesRepository repository = ctx.getBean(BlockedSitesRepository.class);
repository.save(new BlockedSite("https://telegram.org/"));
repository.save(new BlockedSite("https://azure.microsoft.com/"));
}
}
It remains to start the server using Spring Boot and open the corresponding URL on the local host
(localhost:8080/blocked-sites)
. At the same time, our server will return to us a list of sites blocked by us, that is, those sites that we added through the database. Well, it's time to write a client to this server. But before you go to this, you need to remember something.
Theoretical retreat
Let us list some HTTP methods (verbs):
- GET - getting an entity or list;
- POST - create entity;
- PUT - change entity;
- PATCH - change entity (RFC -...);
- DELETE - delete an entity;
- HEAD, OPTIONS - “tricky” methods to support the HTTP protocol and, in general, REST services;
- TRACE is an obsolete method that is not used.
It is impossible not to recall such an important property as idempotency . In simple terms, no matter how many times you use an operation, its result will be the same, as if you applied it only once. For example, you greeted the person in the morning, saying “Hello!” As a result, your friend goes into the “greeted” state :-). And if you say hello several times during the day, nothing will change, it will remain in the same state.
And now, let's think about which of the above HTTP methods are idempotent? Of course, it is implied that you observe semantics. If you do not know, then the teacher tells more about this, starting with the 26th minute of the video.
REST
In order to write a REST controller, you need to remember what REST is:
- REST — REpresentational State Transfer;
- это архитектурный стиль, а не стандарт;
- это, по сути, набор принципов-ограничений;
- REST был давно, но термин появился сравнительно недавно;
- Web-приложение в стиле REST называется RESTful, его API в таком случае — RESTful API (антоним — Stateful);
- REST-ом сейчас называют всё что хотят…
First, if we talk about interaction in the form of a client-server, then it needs to be built in the form of a request-response. Yes, the interaction is not always built that way, but now this interaction is extremely common, and for web applications, something else looks quite strange. And here, for example, web sockets is just not REST.
Secondly, the most important restriction in REST is the lack of client status on the server. It is assumed that the client server always sends all the necessary state with each request, that is, the state is saved on the client side, and there are no sessions on the server.
How to write a client on Spring
To continue work, consider and run the client (use the link to the repository):
git clone git@github.com:ydvorzhetskiy/sb-client.git
mvnw spring-boot:run
This is a client and console application already written, not a web server.
See dependencies:
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.2.RELEASE</version><relativePath/><!-- lookup parent from repository --></parent><groupId>ru.otus</groupId><artifactId>demo-client</artifactId><version>0.0.1-SNAPSHOT</version><url>demo-client</url><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- Это для RestTemplate, это ещё не веб-приложение --><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.1.4.RELEASE</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.8</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.8</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version></dependency><!-- Cache --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- Retry --><dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency><!-- Hystrix --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId><version>2.0.2.RELEASE</version></dependency><dependency><groupId>com.netflix.hystrix</groupId><artifactId>hystrix-javanica</artifactId><version>1.5.12</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
The client has the configuration:
1. RestTemplateConfig.java
package ru.otus.democlient.config;
@Configuration
public classRestTemplateConfig{
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(Duration.ofSeconds(2))
.setReadTimeout(Duration.ofSeconds(3))
.build();
}
2. CacheConfig.java
package ru.otus.democlient.config;
@Configuration
public classCacheConfig{
@Bean
public CacheManager cacheManager() {
returnnew ConcurrentMapCacheManager("sites");
}
}
But the contents of the SiteServiceRest.java file:
package ru.otus.democlient.service;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.List;
@Service
public classSiteServiceRestimplementsSiteService{
private final RestTemplate restTemplate;
private final String serverUrl;
public SiteServiceRest(
RestTemplate restTemplate, @Value("${application.server.url}") String serverUrl
) {
this.restTemplate = restTemplate;
this.serverUrl = serverUrl;
}
@Override
public List<SiteInfo> findAllBlockedSites() {
return restTemplate.exchange(
serverUrl + "/blocked-sites",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<SiteInfo>>() {
}
).getBody();
}
public List<SiteInfo> getDefaultSites() {
return Collections.singletonList(new SiteInfo() {{
setUrl("http://vk.com/");
}});
}
}
Slightly summarize:
- Requests are made via RestTemplate.
- RestTemplate can be customized, and this is a regular bean.
- Jackson is used for mapping JSON into objects.
- Further - only your flight of fancy (details about the launch of the client are in the video).
Colleagues, the webinar turned out to be very informative, therefore, in order not to miss anything, it’s better to watch it completely. You will try a real API "in combat conditions", add
@Cacheable
to the service, work with Spring Retry, learn about Hystrix and much more. We also invite you to the Spring Open Day , which will take place very soon. And, as usual, we are waiting for your comments on the past open lesson!