Http Client Api Java 11
Tags: java, httpclient, api
Published: 2021-03-19 22:58:42

Tem muito tempo que os desenvolvedores java sofrem para trabalhar com HTTP, se não fosse por meio de recursos externos essa solicitação ficava muito verbosa e cansativa. 

Mas nas ultimas release do java tivemos a inclusão da Api cliente padronizada que visa substituir o *HttpURLConnection* que está presente no JDK desde os primeiros anos.

A nova Api suporta HTTP/1.1 e HTTP/2. A versão mais recente do protocolo HTTP foi projetada para melhorar o desempenho geral do envio de solicitações e do recebimento de respostas de um servidor.
Isso aconteceu através da introdução de varias alterações como:
multiplexação de fluxo, compactação de cabeçalho e Push Promise.
Além disso o novo HTPP suporta nativamente *webSockets*.

Ao contrário do HttpURLConnection, o *HttpClient* fornece mecanismos de solicitação síncrona e assíncrona.

## A API consiste em 3 classes principais:

* **HttpRequest** - representa a solicitação a ser enviada por meio do HttpClient
* **HttpClient** - se comporta como um contêiner para informações de configuração comuns a várias solicitações
* **HttpResponse** - representa o resultado de uma chamada HttpRequest

Um exemplo simples 
```
var url = "https://postman-echo.com/get";
		HttpRequest request = HttpRequest.newBuilder()
                .uri(new URI(url))
                .GET()
				.build();
		
		HttpClient httpClient = HttpClient.newHttpClient();
        var response =
                httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return  response.body();
```
 
## Configurando Headers
Podemos usar o *headers* que recebe vários parâmetros ou *header*
que recebe apenas um parâmetro ambos os métodos são chave e valor.

```
		HttpRequest request = HttpRequest.newBuilder()
				.uri(new URI(url))
				.header("Content-Type", "text/plain;charset=UTF-8")
				.GET()
				.build();
```

```
//varios headers
.headers("Content-Type", "application/json", "token", "dadda")
//apenas um header
.header(Content-Type", "application/json")
```

## Requisição com corpo
A nova API fornece várias implementações de *BodyProcessor* prontas para usar, que simplificam a passagem do corpo da solicitação.

* **StringProcessor** - (lê o corpo de uma String , criada com HttpRequest.BodyProcessor.fromString )
* **InputStreamProcessor** - (lê o corpo de um InputStream , criado com HttpRequest.BodyProcessor.fromInputStream )
* **ByteArrayProcessor** - (lê o corpo de uma matriz de bytes, criada com HttpRequest.BodyProcessor.fromByteArray )
* **FileProcessor** - (lê o corpo de um arquivo no caminho fornecido, criado com HttpRequest.BodyProcessor.fromFile )

```
var url = "https://postman-echo.com/post";
		HttpRequest request = HttpRequest.newBuilder()
				.uri(new URI(url))
				.POST(HttpRequest.BodyPublishers.ofString("exemplo"))
				.build();

		HttpClient httpClient = HttpClient.newHttpClient();
		var response =
				httpClient.send(request, HttpResponse.BodyHandlers.ofString());

		return  response.body();
```

O client suporta todos os métodos HTTP, mas o construtor contém apenas esses métodos pré-definidos: GET(), POST(), DELETE(), e PUT(). Para criar uma solicitação com um método HTTP diferente, você precisa chamar method().

```
	var request = HttpRequest.newBuilder(URI.create("https://postman-echo.com/headers"))
			.method("HEAD", BodyPublishers.noBody())
			.build();
```

## Configurações disponíveis 
```
	var client = HttpClient.newBuilder()
			.authenticator(Authenticator.getDefault())
			.connectTimeout(Duration.ofSeconds(30))
			.cookieHandler(CookieHandler.getDefault())
			.executor(Executors.newFixedThreadPool(2))
			.followRedirects(Redirect.NEVER)
			.priority(1) 
			.proxy(ProxySelector.getDefault())
			.sslContext(SSLContext.getDefault())
			.version(HttpClient.Version.HTTP_2) 
			.sslParameters(new SSLParameters())
			.build();
```
Por padrão, o cliente tenta abrir uma conexão HTTP / 2, se o servidor responder com HTTP / 1.1, o cliente retorna automaticamente para esta versão. 

**connectTimeout()** - determina quanto tempo o cliente espera até que uma conexão possa ser estabelecida. Se a conexão não puder ser estabelecida, o cliente lançará uma _HttpConnectTimeoutExceptionexceção_.

**executor()** - define o executor a ser usado para tarefas assíncronas e dependentes.

## Alguns dos métodos fornecidos na interface HttpResponse.
* **body()** - retorna o corpo da resposta
* **headers()** - retorna os cabeçalhos de resposta
* **statusCode()** - retorna o código de status HTTP	
* **version()** - retorna o protocolo HTTP	

## Solicitações assíncrona
O novo HttpClient oferece duas possibilidades para enviar uma solicitação a um servidor:

* **send** de forma síncrona (bloqueia até que a resposta chegue)
* **sendAsync** de forma assíncrona (não espera pela resposta, sem bloqueio)

o método _sendAsync_ retorna CompletableFeature <HttpResponse> - para processar uma solicitação de forma assíncrona :

```
var url = "https://postman-echo.com/post";
		HttpRequest request = HttpRequest.newBuilder()
				.uri(new URI(url))
				.POST(HttpRequest.BodyPublishers.ofString("exemplo"))
				.build();

		HttpClient httpClient = HttpClient.newHttpClient();
		var response =
				httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
				.thenApply(HttpResponse::body)
				.thenAccept(System.out::println);
		return response;
```