Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce RestClient #29552

Closed
poutsma opened this issue Nov 22, 2022 · 21 comments
Closed

Introduce RestClient #29552

poutsma opened this issue Nov 22, 2022 · 21 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@poutsma
Copy link
Contributor

poutsma commented Nov 22, 2022

In Spring Framework 5.0, we introduced the WebClient: a new, reactive HTTP client. Compared to RestTemplate, the previous generation, WebClient improved HTTP access on two fronts:

  • asynchrony, offered through reactive streams, and
  • improved APIs, making it much easier to customize request and response.

With the advent of Project Loom, asynchrony can be obtained through standard, synchronous APIs. We should therefore introduce a version of WebClient that offers the same improved APIs as the current reactive version, but exposes them in a synchronous manner.

@poutsma poutsma added in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement labels Nov 22, 2022
@poutsma poutsma added this to the 6.1.x milestone Nov 22, 2022
@poutsma poutsma self-assigned this Nov 22, 2022
@poutsma poutsma changed the title Loom-ready WebClient Loom-Ready WebClient Nov 22, 2022
@poutsma
Copy link
Contributor Author

poutsma commented Jan 10, 2023

After team discussion, it has been decided that the 6.1 timeline will be too early for us to fully implement a Loom-ready WebClient. There are simply too may unknowns: underlying ClientHttpRequestFactory implementations that yet have to reveal their plans for Loom support, it is unclear what structured concurrency will look like in a Loom environment, and so on.

Implementing a new, Loom-ready WebClient in 6.1 could mean that we end up with something that is not ready for the future. Therefore, we have decided to do experimental work on this issue in parallel to the 6.1 release, but not make the issue part of this release.
Further progress will be provided through this issue.

Note that we are still considering other areas for Loom compatibility for 6.1, including the existing (reactive) WebClient and RestTemplate.

@nightswimmings
Copy link

This is amazing, but please, keep the package server(arch)-agnostic this time (reactive/servlet)

@poutsma poutsma changed the title Loom-Ready WebClient Introduce RestClient Jul 3, 2023
@poutsma poutsma modified the milestones: 6.x Backlog, 6.1.0-M2 Jul 3, 2023
@poutsma
Copy link
Contributor Author

poutsma commented Jul 3, 2023

Spring 6.1 M2 will see the introduction of RestClient, a synchronous HTTP client that offers an API similar to WebClient, using the same infrastructure (i.e. request factory, error handler, interceptors, etc) as RestTemplate.

@ThomasKasene
Copy link

Out of curiosity, why use "Rest" as part of the name if it can be used for anything HTTP-related, such as GraphQL? I admit it's tough to come up with a good, descriptive name that also rolls easily off the tongue, though, especially since "HttpClient" is already taken.

@poutsma
Copy link
Contributor Author

poutsma commented Jul 3, 2023

The prefix Rest reflects that this new client conceptually sits in between RestTemplate and WebClient. Initially we considered having two WebClient classes: a reactive and non-reactive one. But that would cause confusion, so we went for RestClient.

In retrospect, I would not have have given RestTemplate that prefix when it was introduced in Spring 3, because it has little to do with REST. But here we are, and like you said: HttpClient is already taken by Apache, OkHttp, Jetty, and the JDK.

@anbusampath
Copy link

The RestTemplate will be deprecated in a future version and will not have major new features added going forward.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html

with RestClient in place, will RestTemplate get deprecated in 6.1 timeframe?

@poutsma
Copy link
Contributor Author

poutsma commented Jul 5, 2023

The RestTemplate will be deprecated in a future version and will not have major new features added going forward.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html

@anbusampath Please read that page you linked to again, as it does not contain the text you quoted.

with RestClient in place, will RestTemplate get deprecated in 6.1 timeframe?

RestTemplate will not be deprecated; it is in maintenance mode, meaning that it will not have new features.

@anbusampath
Copy link

@anbusampath Please read that page you linked to again, as it does not contain the text you quoted.

sorry my bad, I was reading old doc - https://docs.spring.io/spring-framework/docs/5.2.1.RELEASE/javadoc-api/index.html?org/springframework/web/client/RestTemplate.html and attached latest doc link.
Latest version does not contain the text.

RestTemplate will not be deprecated; it is in maintenance mode, meaning that it will not have new features.

Thanks for the clarification.

@quaff
Copy link
Contributor

quaff commented Jul 5, 2023

RestTemplate will not be deprecated; it is in maintenance mode, meaning that it will not have new features.

@poutsma Could you review this PR #27188? It's not new feature, I think it's a fix or improvement.

@Sineaggi
Copy link

Sineaggi commented Jul 6, 2023

Will this new RestClient support the HttpServiceProxyFactory class along with the @HttpExchange annotated interfaces?

@anbusampath
Copy link

Will this new RestClient support the HttpServiceProxyFactory class along with the @HttpExchange annotated interfaces?

watch this issue - #30117

@vpavic
Copy link
Contributor

vpavic commented Jul 6, 2023

Thanks for making this happen @poutsma (and the team). With RestTemplate being in the maintenance mode, something like this was much needed for all of us that aren't (for whatever the reason) keen on using WebClient.

I'm curious whether the team considered making the new client a part of separate module, rather then having it again (as with RestTemplate) packaged in spring-web that's mostly focused on server-side components? I know that something along these lines was previously discussed (#21301 comes to mind), but I'm in the camp with those that firmly believe that I shouldn't get server-side components if client is all I'm interested in. Besides the fact it has become quite common for frameworks that react on presence of things on classpath, I would say that the likelihood of setups that need just the client in on the rise - Spring Batch comes to mind as it recommends job per JVM approach these days, if I'm not mistaken.

Regarding naming, did you consider going with HttpOperations (implemented by HttpTemplate)? This is more aligned with other places in Spring where we have ...Operations/...Template combination, and avoids using the term REST where it really shouldn't be used. Additionally, it feels to me that RestClient itself isn't really the client itself but rather the convenience layer that abstracts the underlying HTTP client, similar like other ...Operations/...Template combinations do.

@poutsma
Copy link
Contributor Author

poutsma commented Jul 7, 2023

I'm curious whether the team considered making the new client a part of separate module, rather then having it again (as with RestTemplate) packaged in spring-web that's mostly focused on server-side components?

This was not considered. RestClient is closely aligned to RestTemplate, as it uses the same underlying infrastructure and throws the same exceptions. Putting RestClient in a separate module would therefore mean either moving RestTemplate and related types out of the spring-web module—breaking backward compatibility from 6.0, or putting RestClient in a new module all by itself, which is equally unappealing.

Regarding naming, did you consider going with HttpOperations (implemented by HttpTemplate)? This is more aligned with other places in Spring where we have ...Operations/...Template combination, and avoids using the term REST where it really shouldn't be used.

A HttpClient based the Operations/Template design is what we created in RestTemplate 14 years ago, and it quickly became apparent that the API-style that Templates offer is not suitable for HTTP clients, because exposing every capability of HTTP in a Template results in too many overloaded (see RestTemplate). As for the Rest prefix, see my comment above.

Additionally, it feels to me that RestClient itself isn't really the client itself but rather the convenience layer that abstracts the underlying HTTP client, similar like other ...Operations/...Template combinations do.

I am not sure what gave you that feeling, because the WebClient was introduced in 5.0 and "abstract the underlying HTTP clients" in pretty much the same way as RestClient does.

poutsma added a commit that referenced this issue Jul 7, 2023
This commit introduces an overloaded version of RestClient::exchange,
adding a boolean parameter that indicates whether the connection is
closed after the exchange function is executed.

See gh-29552
@vpavic
Copy link
Contributor

vpavic commented Jul 10, 2023

This was not considered. RestClient is closely aligned to RestTemplate, as it uses the same underlying infrastructure and throws the same exceptions. Putting RestClient in a separate module would therefore mean either moving RestTemplate and related types out of the spring-web module—breaking backward compatibility from 6.0, or putting RestClient in a new module all by itself, which is equally unappealing.

I understand that this would be a significant undertaking, and one that wouldn't be fully possible without breaking changes and therefore a new major release. However, IMO RestClient in a new module sounds quite nice, assuming other clients are moved there as well with time (if RestTemplate won't eventually get deprecated and removed).

With the introduction of a modern HTTP client to the JDK itself, it's even more difficult to swallow the extra components you need to put to your classpath in order to use the new RestClient, if you don't need server-side support. Quite honestly, I'd prefer to use the thinnest possible convenience layer around java.net.http.HttpClient (be it from Spring or someone else) simply because I can have the same experience on every type of project while also having minimal impact on the classpath.

I am not sure what gave you that feeling, because the WebClient was introduced in 5.0 and "abstract the underlying HTTP clients" in pretty much the same way as RestClient does.

The same concerns from my end apply to WebClient as well, I'm just not focusing on it as I generally try to avoid reactive, but I think it should've been named (reactive-)HTTP-something. Naming truly is hard, but I would've definitely preferred something that has HTTP in its name and expresses well that it's an abstraction of the underlying client, regardless of the legacy and how others name their clients.

Anyhow, this is (to me) a less important concern to how things are laid out across Spring modules.

@rstoyanchev
Copy link
Contributor

Naming is hard, and it's not always about picking the most logical name. The choice has to be made in a specific context, and in the given context the chosen name is good. The RestTemplate, even if imperfectly named, has been used for so long and widely that it carries very deep associations. RestClient is good as a layer around the same infrastructure and in the same package.

The Spring Framework has many clients, two HTTP clients, two WebSocket clients, SockJsClient, TCP client, STOMP client, RSocket client, DatabaseClient, and not even counting the various templates for JDBC, JMS. Across Spring projects there are many more. There would be many new jars down this road, tempting as it might look for one case, I'm not sure the overall end result is a better place.

Many of those clients support different underlying libraries. It's not clear if you actually want this split even further, e.g. one HTTP client jar for the JDK client, another for Jetty, another for Apache HTTP Components, and so on, but clearly that would be even more jars, or otherwise you still have a jar with some optional dependencies at least. Our view is that we try to structure modules but any optional dependencies within should not have impact you in any way as long as the classes are not used.

@vpavic
Copy link
Contributor

vpavic commented Jul 11, 2023

Many of those clients support different underlying libraries. It's not clear if you actually want this split even further, e.g. one HTTP client jar for the JDK client, another for Jetty, another for Apache HTTP Components, and so on, but clearly that would be even more jars, or otherwise you still have a jar with some optional dependencies at least. Our view is that we try to structure modules but any optional dependencies within should not have impact you in any way as long as the classes are not used.

My preference would be to have a single Spring module that carries all the HTTP-client related code, with supported underlying libraries being expressed through optional dependencies.

On projects I work on I'm really picky about what I put on the classpath and really like to avoid having anything that's not really necessary. So I'm never thrilled to see server- and client-side components mixed together.

My own preferences aside, there are numerous benefits of keeping the two apart:

  • not having to worry what will get auto-configured by mere presence of the components I don't need on the classpath (also, what works today could have different behavior tomorrow meaning I have additional maintenance costs due to things I don't need/use) and avoiding the related workarounds
  • as HTTP client is not really tied to the runtime (meaning, it makes sense to use reactive HTTP client on Servlet runtime) the split would mean someone doesn't need to have server-side components from an entirely different runtime on the classpath - pretty sure this could also translate into some simplifications in Spring Boot's auto-configuration
  • security aspect: all those (brilliant) security scanners will scream at me if there's a CVE reported for some Spring module even if the potential vulnerability isn't event in the components I use (see Sonatype vulnerability CVE-2016-1000027 in Spring-web project #24434 as an example of that) so why would an application that uses only client-side components be affected by a vulnerability in server-side components (and vice-versa)?

@wimdetroyer
Copy link

wimdetroyer commented Nov 29, 2023

Does RestClient have a variant for use in testing like RestTemplate had with TestRestTemplate ?

See also: https://github.com/spring-projects/spring-boot/blob/6fd691af589f1b85a492e3d6660dac5d15ba18c6/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc#testresttemplate

Is the alternative using the WebTestClient here?

EDIT: issue tracking this #31275

@rstoyanchev
Copy link
Contributor

@wimdetroyer, TestRestTemplate is part of the Spring Boot test support. It's a simple helper to configure a RestTemplate for integration testing against your server. It's up to the Boot team to consider what similar support for RestClient looks like.

In the mean time, you can bridge TestRestTemplate to RestClient:

@Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
    RestClient restClient = RestClient.create(restTemplate.getRestTemplate());
    // ...    
}

@ViktorDimitrovFT
Copy link

ViktorDimitrovFT commented Jan 4, 2024

Does RestClient have a retry mechanism support? How we can configure the client to retry requests when specific exception is thrown?

@wimdetroyer
Copy link

wimdetroyer commented Jan 4, 2024

Does RestClient have a retry mechanism support? How we can configure the client to retry requests when specific exception is thrown?

Use spring retry

@making
Copy link
Member

making commented Jan 4, 2024

RestClient can use the same interface as RestTemplate for inserting retry processes, which is the ClientHttpRequestInterceptor. For an example of a ClientHttpRequestInterceptor with retry logic, you can refer to this GitHub repository: https://github.com/making/retryable-client-http-request-interceptor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests