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

HTTP interface client infrastructure and adapter for RestTemplate #30117

Closed
ooraini opened this issue Mar 14, 2023 · 2 comments
Closed

HTTP interface client infrastructure and adapter for RestTemplate #30117

ooraini opened this issue Mar 14, 2023 · 2 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@ooraini
Copy link

ooraini commented Mar 14, 2023

Affects: <Spring Framework version>


The new HTTP interface clients only supports WebClient, for MVC users this means an additional dependency on web-flux and dealing with Spring boot auto configuration for web-flux.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 14, 2023
@rstoyanchev rstoyanchev added in: web Issues in web modules (web, webmvc, webflux, websocket) and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Mar 14, 2023
@rstoyanchev
Copy link
Contributor

rstoyanchev commented Mar 14, 2023

hi @ooraini, thanks for bringing this up.

HttpClientAdapter can be implemented quite easily with the RestTemplate. For example:

RestTemplateAdapter

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.service.invoker.HttpClientAdapter;
import org.springframework.web.service.invoker.HttpRequestValues;


public class RestTemplateAdapter implements HttpClientAdapter {

	private final RestTemplate restTemplate;


	public RestTemplateAdapter(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}


	@Override
	public Mono<Void> requestToVoid(HttpRequestValues values) {
		this.restTemplate.exchange(newRequest(values), Void.class);
		return Mono.empty();
	}

	@Override
	public Mono<HttpHeaders> requestToHeaders(HttpRequestValues values) {
		HttpHeaders headers = this.restTemplate.exchange(newRequest(values), Void.class).getHeaders();
		return Mono.just(headers);
	}

	@Override
	public <T> Mono<T> requestToBody(HttpRequestValues values, ParameterizedTypeReference<T> type) {
		T body = this.restTemplate.exchange(newRequest(values), type).getBody();
		return Mono.justOrEmpty(body);
	}

	@Override
	public <T> Flux<T> requestToBodyFlux(HttpRequestValues values, ParameterizedTypeReference<T> type) {
		throw new UnsupportedOperationException("Not supported with RestTemplate");
	}

	@Override
	public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues values) {
		ResponseEntity<Void> entity = this.restTemplate.exchange(newRequest(values), Void.class);
		return Mono.just(entity);
	}

	@Override
	public <T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestValues values, ParameterizedTypeReference<T> type) {
		ResponseEntity<T> entity = this.restTemplate.exchange(newRequest(values), type);
		return Mono.just(entity);
	}

	@Override
	public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues values, ParameterizedTypeReference<T> type) {
		throw new UnsupportedOperationException("Not supported with RestTemplate");
	}

	@SuppressWarnings("ReactiveStreamsUnusedPublisher")
	private RequestEntity<?> newRequest(HttpRequestValues values) {

		HttpMethod httpMethod = values.getHttpMethod();
		Assert.notNull(httpMethod, "HttpMethod is required");

		RequestEntity.BodyBuilder builder;

		if (values.getUri() != null) {
			builder = RequestEntity.method(httpMethod, values.getUri());
		}
		else if (values.getUriTemplate() != null) {
			builder = RequestEntity.method(httpMethod, values.getUriTemplate(), values.getUriVariables());
		}
		else {
			throw new IllegalStateException("Neither full URL nor URI template");
		}

		builder.headers(headers -> headers.putAll(values.getHeaders()));
		// TODO: cookies

		if (values.getBodyValue() != null) {
			builder.body(values.getBodyValue());
		}
		else if (values.getBody() != null) {
			throw new IllegalArgumentException("Publisher body is not supported");
		}

		return builder.build();
	}

}

Mainly, it's the Flux methods that are excluded as those cannot be supported with the RestTemplate, and likewise, it's not an option to use Flux or Mono as inputs in @HttpExchange methods either. Aside from that, the rest should work.

There are a couple of things we can consider as part of this request:

  1. Providing an implementation like the one above.
  2. Supporting an alternative HttpClientAdapter contract that does not depend on Reactor.

The work for #29552 should also help to inform decisions we make here. In particular of interest is whether a Loom-friendly contract would support asynchronous requests, and streaming with decoding to objects.

@rstoyanchev rstoyanchev added this to the 6.x Backlog milestone Mar 14, 2023
@rstoyanchev rstoyanchev added the type: enhancement A general enhancement label Mar 14, 2023
@rstoyanchev rstoyanchev self-assigned this Mar 27, 2023
@rstoyanchev rstoyanchev removed their assignment Apr 24, 2023
@rstoyanchev rstoyanchev modified the milestones: 6.x Backlog, 6.1.0-M2 Apr 24, 2023
@OlgaMaciaszek
Copy link
Contributor

We are going to experiment with this for 6.1.

@rstoyanchev rstoyanchev self-assigned this Jun 19, 2023
rstoyanchev added a commit that referenced this issue Jul 11, 2023
rstoyanchev added a commit that referenced this issue Jul 11, 2023
Now that HttpClientAdapter is deprecated and replaced by HttpExchangeAdapter
and ReactorHttpExchangeAdapter, our tests should use the new contracts.

See gh-30117
rstoyanchev added a commit that referenced this issue Jul 11, 2023
rstoyanchev added a commit that referenced this issue Jul 11, 2023
HTTP interface client argument resolvers for RequestBody and
RequestPart now handle reactive input conditionally.

See gh-30117
@rstoyanchev rstoyanchev changed the title HttpClientAdapter for RestTemplate HTTP interface client infrastructure and adapter for RestTemplate Jul 11, 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: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants