[Spring] Kotlin Fuel

MAY 31, 2022

■ Fuel

  • The easiest HTTP networking library for Kotlin/Android.
  • request, response, result 를 구조분해하여 편리하게 가져다 쓸 수 있다.
  • Asynchronous 와 blocking 을 제공한다.
  • async request 취소기능 제공
  • Upload files 기능을 제공

■ Async mode

// Using httpGet() over a String is giving us a Triple<Request, Response, Result>.

"https://httpbin.org/get".httpGet().responseString { request, response, result ->
  when (result) {
    is Result.Failure -> {
      val errorData = String(result.error.errorData)
    }
    is Result.Success -> {
      val data = result.get()
    }
  }
}

FuelManager.instance.basePath = "https://httpbin.org"
"/get".httpGet().responseString { request, response, result ->
    val (data, error) = result
    if (error == null) {
        //do something when success
    } else {
        //error handling
    }
}

■ Blocking mode

// Using httpGet() over a String is giving us a Triple<Request, Response, Result>.
    
val (request, response, result) = "https://httpbin.org/get"
    .httpGet()
    .responseString() 

■ Result

  • operation 의 결과 (success or failure) 를 포함하고 있는 functional-style data structure
fun response(handler: (Request, Response, Result<ByteArray, FuelError>) -> Unit)

fun responseString(handler: (Request, Response, Result<String, FuelError>) -> Unit)

fun responseJson(handler: (Request, Response, Result<Json, FuelError>) -> Unit)
val jsonObject = json.obj() //JSONObject
val jsonArray = json.array() //JSONArray


fun <T> responseObject(deserializer: ResponseDeserializable<T>, handler: (Request, Response, Result<T, FuelError>) -> Unit)

■ 무엇이 쉽나

Adding Parameters

URL encoded style for GET and DELETE request

Fuel.get("https://httpbin.org/get", listOf("foo" to "foo", "bar" to "bar"))
    .url
// https://httpbin.org/get?foo=foo&bar=bar

Support x-www-form-urlencoded for PUT, POST and PATCH

Fuel.post("https://httpbin.org/post", listOf("foo" to "foo", "bar" to "bar"))
    .also { println(it.url) }
    .also { println(String(it.body().toByteArray())) }

// https://httpbin.org/post
// "foo=foo&bar=bar"

Adding Request Body use application/json

Fuel.post("https://httpbin.org/post")
    .jsonBody("{ \"foo\" : \"bar\" }")
    .also { println(it) }
    .response { result -> }

Adding Progress callbacks

Request progress

Fuel.post("/post")
    .body(/*...*/)
    .requestProgress { readBytes, totalBytes ->
      val progress = readBytes.toFloat() / totalBytes.toFloat() * 100
      println("Bytes uploaded $readBytes / $totalBytes ($progress %)")
    }
    .response { result -> }

Response progress

Fuel.get("/get")
    .responseProgress { readBytes, totalBytes ->
      val progress = readBytes.toFloat() / totalBytes.toFloat() * 100
      println("Bytes downloaded $readBytes / $totalBytes ($progress %)")
    }
    .response { result -> }

Using multipart/form-data(UploadRequest)

Fuel.upload("/post")
    .add { FileDataPart(File("myfile.json"), name = "fieldname", filename="contents.json") }
    .response { result -> }

Fuel.upload("/post")
    .add(
        FileDataPart(File("myfile.json"), name = "files[]", filename="contents.json"),
        FileDataPart(File("myfile2.json"), name = "files[]", filename="contents2.json"),
        FileDataPart(File("myfile3.json"), name = "files[]", filename="contents3.json")
    )
    .response { result -> }

Cancle an async Request

val request = Fuel.get("https://httpbin.org/get")
  .interrupt { request -> println("${request.url} was interrupted and cancelled") }
  .response { result ->
    // if request is cancelled successfully, response callback will not be called.
    // Interrupt callback (if provided) will be called instead
  }

request.cancel() // this will cancel on-going request

Debug Logging

val request = Fuel.post("https://httpbin.org/post", parameters = listOf("foo" to "foo", "bar" to "bar", "key" to "value"))
println(request.cUrlString())

// curl -i -X POST -d "foo=foo&bar=bar&key=value" -H "Accept-Encoding:compress;q=0.5, gzip;q=1.0" -H "Device:Android" -H "Content-Type:application/x-www-form-urlencoded" "https://httpbin.org/post"

Asynchronous API

non-blocking asynchronous request 를 보통 사용한다고 하는데 이는 무엇인가?
먼저 Async, Sync & Blocking, Non-Blocking 의 차이를 살펴보자
작업을 요청하는 클라이언트 : A
작업을 수행해서 결과를 return : B

Sync & Async : 작업의 주체성을 누가 갖는가 => A / B
Blocking & Non-Blocking : 로직의 흐름 => 멈춘다. / 안 멈춘다.

Sync-Blocking : A 는 B 가 완료할 때까지 계속 기다린다.
Sync-Non-Blocking : A 가 작업의 주체성을 갖고 있으며, B 가 작업을 완료할 때까지 핑퐁하면서 완료 여부를 체크한다.

Non-Blocking : B 가 A 에게
Async-Blocking : A 가 넘겨준 콜백 함수를 B 가 실행하고 완료하는 것을 기다린다.
Async-Non-Blocking : A 가 B 에게 콜백 함수를 넘겨주고 A 는 자신의 일을 계속 진행하다가 B 가 작업 완료하면 A 가 넘겨 준 콜백 함수를 수행한다.

fuel doc

https://fuel.gitbook.io/documentation/core/fuel#using-multipart-form-data-uploadrequest

fuel github

https://github.com/kittinunf/fuel https://github.com/kittinunf/fuel/blob/master/README-legacy.md

https://medium.com/swlh/is-fuel-an-alternative-for-retrofit-f81bd4505a87

webclient vs resttemplate

https://tecoble.techcourse.co.kr/post/2021-10-20-synchronous-asynchronous/

■ 제목입니당 ■ 서브제목입니당 ■ 서브제목2입니당

  • This is green color text
  • This is red color text
  • This is blue color text

안녕

안녕

안녕

안녕

안녕

이미지

- hello
+ green
! orange
# gray

작업 기록 블로그