Solicitações HTTP com Kotlin e khttp
1. Introdução
O protocolo HTTP e as APIs construídas nele são de importância central na programação atualmente.
Na JVM, temos várias opções disponíveis, de bibliotecas de nível inferior a muito alto, de projetos estabelecidos a novos garotos. No entanto, a maioria deles é direcionada principalmente para programas Java.
Neste artigo,we’re going to look at khttp, an idiomatic Kotlin library for consuming HTTP-based resources e APIs.
2. Dependências
Para usar a biblioteca em nosso projeto, primeiro precisamos adicioná-la às nossas dependências:
khttp
khttp
0.1.0
Como ainda não está no Maven Central, também precisamos habilitar o repositório do JCenter:
central
http://jcenter.bintray.com
A versão 0.1.0 é a atual no momento da escrita. Podemos, é claro,check JCenter for a newer one.
3. Uso básico
O básico do protocolo HTTP é simples, embora os detalhes possam ser bastante complicados. Portanto, o khttp também possui uma interface simples.
For every HTTP method, we can find a package-level function in the khttp package, comoget,post e assim por diante.
Todas as funções recebem o mesmo conjunto de argumentos e retornam um objetoResponse; veremos os detalhes disso nas seções a seguir.
No decorrer deste artigo, usaremos o formulário totalmente qualificado, por exemplo,khttp.put. Em nossos projetos, é claro, podemos importar e possivelmente renomear esses métodos:
import khttp.delete as httpDelete
Note: we’ve added type declarations for clarity throughout code examples porque sem um IDE eles podem ser difíceis de seguir.
4. Um pedido simples
Every HTTP request has at least two required components: a method and a URL. Em khttp, o método é determinado pela função que invocamos, como vimos na seção anterior.
A URL é o único argumento necessário para o método; portanto, podemos executar facilmente uma solicitação simples:
khttp.get("http://httpbin.org/get")
Nas seções a seguir, consideraremos todas as solicitações para serem concluídas com sucesso.
4.1. Adicionando parâmetros
Geralmente, precisamos fornecer parâmetros de consulta além do URL base, especialmente para solicitações GET.
khttp’s methods accept a params argument que é umMap dos pares de valores-chave a serem incluídos na consultaString:
khttp.get(
url = "http://httpbin.org/get",
params = mapOf("key1" to "value1", "keyn" to "valuen"))
Observe que usamos a funçãomapOf para construir umMap instantaneamente; o URL de solicitação resultante será:
http://httpbin.org/get?key1=value1&keyn=valuen
5. Um corpo de solicitação
Outra operação comum que geralmente precisamos executar é o envio de dados, normalmente como a carga útil de uma solicitação POST ou PUT.
Para isso, a biblioteca oferece várias opções que examinaremos nas próximas seções.
5.1. Envio de uma carga JSON
We can use the json argument to send a JSON object or array. Pode ser de vários tipos diferentes:
-
AJSONObject ouJSONArray conforme fornecido pela biblioteca org.json
-
AMap, que é transformado em um objeto JSON
-
ACollection,Iterable ou matriz, que é transformada em uma matriz JSON
Podemos facilmente transformar nosso exemplo anterior de GET em um POST que enviará um objeto JSON simples:
khttp.post(
url = "http://httpbin.org/post",
json = mapOf("key1" to "value1", "keyn" to "valuen"))
Observe que a transformação de coleções em objetos JSON é superficial. Por exemplo, umList deMap's não será convertido em uma matriz JSON de objetos JSON, mas sim em uma matriz de strings.
Para conversão profunda, precisaríamos de uma biblioteca de mapeamento JSON mais complexa, como Jackson. O recurso de conversão da biblioteca é destinado apenas a casos simples.
5.2. Envio de dados de formulário (codificado por URL)
Para enviar dados de formulário (codificados em URL, como em formulários HTML), usamos o argumentodata com umMap:
khttp.post(
url = "http://httpbin.org/post",
data = mapOf("key1" to "value1", "keyn" to "valuen"))
5.3. Carregando arquivos (formulário multiparte)
Podemos enviar um ou mais arquivos codificados como uma solicitação de dados de formulário com várias partes.
Nesse caso, usamos o argumentofiles:
khttp.post(
url = "http://httpbin.org/post",
files = listOf(
FileLike("file1", "content1"),
FileLike("file2", File("kitty.jpg"))))
Podemos ver que khttp usa uma abstraçãoFileLike, que é um objeto com um nome e um conteúdo. O conteúdo pode ser uma string, uma matriz de bytes,File ouPath.
5.4. Envio de conteúdo bruto
Se nenhuma das opções acima for adequada, podemos usar umInputStream para enviar dados brutos como o corpo de uma solicitação HTTP:
khttp.post(url = "http://httpbin.org/post", data = someInputStream)
Nesse caso, provavelmente também precisaremos definir manualmente alguns cabeçalhos, que abordaremos em uma seção posterior.
6. Lidando com a Resposta
Até agora, vimos várias maneiras de enviar dados para um servidor. Mas muitas operações HTTP são úteis por causa dos dados que eles retornam também.
khttp é baseado no bloqueio de E / S, portantoall functions corresponding to HTTP methods return a Response object contendo a resposta recebida do servidor.
Este objeto possui várias propriedades que podemos acessar, dependendo do tipo de conteúdo.
6.1. Respostas JSON
Se sabemos que a resposta é um objeto JSON ou matriz, podemos usar as propriedadesjsonObjectejsonArray:
val response : Response = khttp.get("http://httpbin.org/get")
val obj : JSONObject = response.jsonObject
print(obj["someProperty"])
6.2. Respostas de texto ou binárias
Se quisermos ler a resposta comoString, podemos usar a propriedadetext:
val message : String = response.text
Ou, se quisermos ler como dados binários (por exemplo, um download de arquivo) usamos a propriedadecontent:
val imageData : ByteArray = response.content
Finalmente, também podemos acessar oInputStream subjacente:
val inputStream : InputStream = response.raw
7. Uso Avançado
Vamos também dar uma olhada em alguns padrões de uso mais avançados que são geralmente úteis e que ainda não tratamos nas seções anteriores.
7.1. Manipulação de cabeçalhos e cookies
All khttp functions take a headers argument que é umMap dos nomes e valores dos cabeçalhos.
val response = khttp.get(
url = "http://httpbin.org/get",
headers = mapOf("header1" to "1", "header2" to "2"))
Da mesma forma para os cookies:
val response = khttp.get(
url = "http://httpbin.org/get",
cookies = mapOf("cookie1" to "1", "cookie2" to "2"))
Também podemos acessar cabeçalhos e cookies enviados pelo servidor na resposta:
val contentType : String = response.headers["Content-Type"]
val sessionID : String = response.cookies["JSESSIONID"]
7.2. Tratamento de erros
Existem dois tipos de erros que podem surgir no HTTP: respostas a erros, como 404 - Não encontrado, que fazem parte do protocolo; e erros de baixo nível, como "conexão recusada".
O primeiro tipo não resulta em exceções de lançamento de khttp; em vez disso,we should check the Response statusCode property:
val response = khttp.get(url = "http://httpbin.org/nothing/to/see/here")
if(response.statusCode == 200) {
process(response)
} else {
handleError(response)
}
Em vez disso, os erros de nível inferior resultam em exceções lançadas do subsistema de E / S Java subjacente, comoConnectException.
7.3. Respostas de streaming
Às vezes, o servidor pode responder com grande parte do conteúdo e / ou demorar muito para responder. Nesses casos, podemos querer processar a resposta em partes, em vez de esperar que ela complete e ocupe memória.
Se quisermos instruir a biblioteca a nos dar uma resposta de streaming, temos que passartrue como o argumentostream:
val response = khttp.get(url = "http://httpbin.org", stream = true)
Em seguida, podemos processá-lo em pedaços:
response.contentIterator(chunkSize = 1024).forEach { arr : ByteArray -> handleChunk(arr) }
7.4. Métodos Não Padrão
No caso improvável de precisarmos usar um método HTTP (ou verbo) que khttp não fornece nativamente - digamos, para alguma extensão do protocolo HTTP, como WebDAV - ainda estaremos cobertos.
Na verdade, todas as funções no pacote khttp, que correspondem aos métodos HTTP, são implementadas usando uma funçãorequest genérica que também podemos usar:
khttp.request(
method = "COPY",
url = "http://httpbin.org/get",
headers = mapOf("Destination" to "/copy-of-get"))
7.5. Outras características
Não tocamos em todos os recursos do khttp. Por exemplo, não discutimos tempos limites, redirecionamentos e histórico ou operações assíncronas.
The official documentation é a fonte final de informações sobre a biblioteca e todos os seus recursos.
8. Conclusão
Neste tutorial, vimos como fazer solicitações HTTP em Kotlin com a biblioteca idiomática khttp.
A implementação de todos esses exemplos pode ser encontrada emthe GitHub project - este é um projeto Maven, portanto, deve ser fácil de importar e executar como está.