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

Create migration guide from RestTemplate to RestClient #23269

Closed
membersound opened this issue Jul 10, 2019 · 10 comments
Closed

Create migration guide from RestTemplate to RestClient #23269

membersound opened this issue Jul 10, 2019 · 10 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: documentation A documentation task
Milestone

Comments

@membersound
Copy link

membersound commented Jul 10, 2019

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

Could you add a detailed migration guide on how to refactor existing RestTemplate (which typically is for sync blocking requests) into WebClient requests (also sync and blocking)?

Because the usual case for WebClient is probably for async requests, but chances are high that if someone refactors to WebClient he want's to stick to his synchronous patterns.

Wouldn't this be a good idea to grab spring users by their hands just now, if it's planned to deprecate RestTemplate in future anyhow?

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 10, 2019
@sbrannen sbrannen added type: documentation A documentation task for: team-attention in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jul 10, 2019
@sbrannen sbrannen changed the title Migration Guide from RestTemplate to WebClient? Create migration guide from RestTemplate to WebClient Jul 10, 2019
@rstoyanchev
Copy link
Contributor

That is a good idea to put together such a a resource for those only familiar with the RestTemplate and simply concerned about its potential deprecation, and not necessarily familiar or even interested in the reactive features.

Note that there is a section in the reference on synchronous use of the WebClient, although we seem to be missing links to it from the content on the RestTemplate. Simply using the WebClient with block is quite straight forward, so definitely read that and give it a try.

Beyond that even if not interested in "reactive", any time you need to do more than one call, there is a good chance simply blocking your way out of each call is missing the power of the WebClient as well as how you can use it in Spring MVC. So I would encourage reading up on the WebClient and learning how to compose multiple calls with it. You can also have a look at this talk of mine which is roughly in that area and starts with RestTemplate.

@membersound
Copy link
Author

If you'll be extending the documentations, maybe you could also go into detail on how to properly log http message body for both request and response in case of sync calls?

For example in RestTemplate it was as easy as adding a ClientHttpRequestInterceptor that just logs the bodies. Together with a BufferingClientHttpRequestFactory is was simply possible to read (log) the body, and then continue the normal flow with the response body in memory.

Yet I did not succeed creating the same for a WebClient, if possible at all?...

@rstoyanchev
Copy link
Contributor

@membersound, good question. You'd probably need to wrap at the connector in order to get to the lower level ClientHttpResponse which then allows you to intercept the body. I haven't tested this but something like this:

public class LoggingConnector implements ClientHttpConnector {

    private final ClientHttpConnector delegate;


    public LoggingConnector(ClientHttpConnector connector) {
        this.delegate = connector;
    }


    @Override
    public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
            Function<? super ClientHttpRequest, Mono<Void>> requestCallback) {

        return this.delegate.connect(method, uri, requestCallback).map(LoggingResponse::new);
    }


    private static class LoggingResponse extends ClientHttpResponseDecorator {

        private static final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();


        private final DataBuffer buffer = bufferFactory.allocateBuffer();


        LoggingResponse(ClientHttpResponse delegate) {
            super(delegate);
        }


        @Override
        public Flux<DataBuffer> getBody() {
            return super.getBody()
                    .doOnNext(this.buffer::write)
                    .doOnComplete(() -> {
                        // Log buffer
                    });
        }
    }

}

@rstoyanchev rstoyanchev added this to the 5.x Backlog milestone Jul 18, 2019
@rstoyanchev rstoyanchev removed the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 18, 2019
@membersound
Copy link
Author

membersound commented Jul 18, 2019

Interesting approach! I think you could just as well use buf.asByteBuffer() on the DataBuffer instead of writing it to another buffer in getBody():

.doOnNext(buf -> LOGGER.info(StandardCharsets.UTF_8.decode(buf.asByteBuffer()).toString()))

It would be a plus if one could also access the ClientResponse somehow inside getBody(), so one could log both http headers + body in one place.

Do you have a further idea how the request-body could also be intercepted within the same connector?

@membersound
Copy link
Author

Would the following be correct?

		private class LoggingRequest extends ClientHttpRequestDecorator {
			public LoggingRequest(ClientHttpRequest delegate) {
				super(delegate);
			}

			@Override
			public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
				return DataBufferUtils.join((Publisher<DataBuffer>) body).flatMap(buf -> {
					LOGGER.info(StandardCharsets.UTF_8.decode(buf.asByteBuffer()).toString());
					return super.writeWith(Mono.fromSupplier(() -> buf));
				});
			}
		}

Or would I also have to override writeAndFlushWith() (how)?

@membersound
Copy link
Author

membersound commented Aug 12, 2019

Interesting approach! I think you could just as well use buf.asByteBuffer() on the DataBuffer instead of writing it to another buffer in getBody():

To correct myself: no, it's not possible to directly write the buffer out. Because the payload may be chunked and then also log chunked content. Instead, collect it inside another DataBuffer and log it on complete is correct.

But I'm using .doOnTerminate() instead of onComplete() to also log error responses.

@rstoyanchev
Copy link
Contributor

Team Decision: This is a good idea, it needs to be done. It won't be part of the Spring Framework reference -- to avoid bloating it and also because such a guide would go beyond this projects (e.g. some parts would relate to Boot). It should rather be an independent guide, perhaps under https://github.com/spring-guides, but it makes sense to leave the ticket here for now.

@billNaylor
Copy link

Has there been any progress on this, I could not find a guide at: https://github.com/spring-guides

@ingogriebsch
Copy link

I would like to repeat @billNaylor question... Has there been any progress on this? It would be really helpful to understand in more detail how to migrate from a RestTemplate to a WebClient (especially if not switching from an imperative stack to a reactive stack).

@anbusampath
Copy link

With Introduction of RestClient , we should be looking for RestTemplate to RestClient migration guide, since RestClient uses same underlying RestTemplate infrastructure.

@jhoeller jhoeller changed the title Create migration guide from RestTemplate to WebClient Create migration guide from RestTemplate to RestClient Jul 13, 2023
@jhoeller jhoeller modified the milestones: 6.x Backlog, 6.1.x Jul 13, 2023
@poutsma poutsma modified the milestones: 6.1.x, 6.1.0-RC1 Oct 3, 2023
@poutsma poutsma closed this as completed in 2b47b89 Oct 4, 2023
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: documentation A documentation task
Projects
None yet
Development

No branches or pull requests

9 participants