# README

[![mavenCentral](https://maven-badges.herokuapp.com/maven-central/com.github.kittinunf.fuel/fuel/badge.svg)](https://search.maven.org/search?q=g:com.github.kittinunf.fuel) [![Build Status](https://travis-ci.org/kittinunf/fuel.svg?branch=master)](https://travis-ci.org/kittinunf/fuel) [![Codecov](https://codecov.io/github/kittinunf/fuel/coverage.svg?branch=master)](https://codecov.io/gh/kittinunf/fuel)

The easiest HTTP networking library for Kotlin/Android.

> You are looking at the documentation for **2.x.y.**. If you are looking for the documentation for **1.x.y**, checkout [the 1.16.0 README.md](https://github.com/kittinunf/Fuel/blob/1.16.0/README.md)

## Features

* [x] HTTP `GET`/`POST`/`PUT`/`DELETE`/`HEAD`/`PATCH` requests in a fluent style interface
* [x] Asynchronous and blocking requests
* [x] Download as a file
* [x] Upload files, `Blob`s, `DataPart`s as `multipart/form-data`
* [x] Cancel asynchronous request
* [x] Debug logging / convert to cUrl call
* [x] Deserialization into POJO / POKO
* [x] Requests as [coroutines](https://github.com/Kotlin/kotlinx.coroutines)
* [x] API Routing

## Installation

We offer maven and jitpack installations. Maven via bintray only has stable releases but jitpack can be used to build any branch, commit and version.

### Maven

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `Fuel` with `Maven` and `Gradle`. The core package has the following dependencies:

* Kotlin - [![Kotlin](https://img.shields.io/badge/Kotlin-1.4.10-blue.svg)](https://kotlinlang.org)
* [Result ](https://github.com/kittinunf/result/)- 3.1.0

```groovy
  //core
  implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
  
  //packages
  implementation 'com.github.kittinunf.fuel:<package>:<latest-version>'
```

Make sure to include `mavenCentral()` in your repositories (`jcenter()` is deprecated, new releases starting from 2.2.3 are hosted on `mavenCentral()`)

```groovy
repositories {
  mavenCentral()
}
```

Each of the extensions / integrations has to be installed separately.

| Package                                                                                   | Description                                                                                                                          |
| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| [`fuel`](/documentation/core/fuel)                                                        | Core package                                                                                                                         |
| [`fuel-android`](/documentation/support/fuel-android)                                     | *Android*: Automatically invoke handler on Main Thread when using Android Module                                                     |
| [`fuel-coroutines`](/documentation/support/fuel-coroutines)                               | *KotlinX*: Execution with [coroutines](https://github.com/Kotlin/kotlinx.coroutines)                                                 |
| [`fuel-forge`](/documentation/deserialization/fuel-forge)                                 | *Deserialization*: [`Forge`](https://github.com/kittinunf/Forge/)                                                                    |
| [`fuel-gson`](/documentation/deserialization/fuel-gson)                                   | *(De)serialization*: [`Gson`](https://github.com/google/gson)                                                                        |
| [`fuel-jackson`](/documentation/deserialization/fuel-jackson)                             | *Deserialization*: [`Jackson`](https://github.com/FasterXML/jackson-module-kotlin)                                                   |
| [`fuel-json`](/documentation/deserialization/fuel-json)                                   | *Deserialization*: [`Json`](http://www.json.org/)                                                                                    |
| [`fuel-kotlinx-serialization`](/documentation/deserialization/fuel-kotlinx-serialization) | *(De)serialization*: [`KotlinX Serialization`](https://github.com/Kotlin/kotlinx.serialization)                                      |
| [`fuel-livedata`](/documentation/support/fuel-livedata)                                   | *Android Architectures*: Responses as [`LiveData`](https://developer.android.com/topic/libraries/architecture/livedata.html)         |
| [`fuel-moshi`](/documentation/deserialization/fuel-moshi)                                 | *Deserialization*: [`Moshi`](https://github.com/square/moshi)                                                                        |
| [`fuel-reactor`](/documentation/support/fuel-reactor)                                     | *Reactive Programming*: Responses as [`Mono`](https://projectreactor.io/docs/core/release/reference/#mono) (**Project Reactor 3.x**) |
| [`fuel-rxjava`](/documentation/support/fuel-rxjava)                                       | *Reactive Programming*: Responses as [`Single`](http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Single.html) (**RxJava 2.x**)    |
| [`fuel-stetho`](https://github.com/kittinunf/fuel/blob/master/fuel-stetho/README.md)      | *Utility*: Debug utility for Android on Chrome Developer Tools, [`Stetho`](https://github.com/facebook/stetho)                       |

### Jitpack

If you want a SNAPSHOT distribution, you can use [`Jitpack`](https://jitpack.io/#kittinunf/fuel)

```kotlin
repositories {
  maven(url = "https://www.jitpack.io") {
    name = "jitpack"
  }
}

dependencies {
  //core
  implementation(group = "com.github.kittinunf.fuel", name = "fuel", version = "-SNAPSHOT")
  
  //packages
  // replace <package> with the package name e.g. fuel-coroutines
  implementation(group = "com.github.kittinunf.fuel", name = "<package>", version = "-SNAPSHOT")
}
```

or

```kotlin
dependencies {
  //core and/or packages
  // replace <package> with the package name e.g. fuel-coroutines
  listof("fuel", "<package>").forEach {
    implementation(group = "com.github.kittinunf.fuel", name = it, version = "-SNAPSHOT")
  }
}
```

#### Configuration

* `group` is made up of `com.github` as well as username and project name
* `name` is the subproject, this may be any of the packages listed in the [installation instructions](https://github.com/kittinunf/fuel#installation) eg. `fuel`, `fuel-coroutines`, `fuel-kotlinx-serialization`, etc
* `version` can be the latest `master-SMAPSHOT` or `-SNAPSHOT` which always points at the HEAD or any other branch, tag or commit hash, e.g. as listed on [jitpack.io](https://jitpack.io/#kittinunf/fuel).

We recommend *not* using `SNAPSHOT` builds, but a specific commit in a specific branch (like a commit on master), because your build will then be stable.

#### Build time-out

Have patience when updating the version of fuel or building for the first time as jitpack will build it, and this may cause the request to jitpack to time out. Wait a few minutes and try again (or check the status on jitpack).

**NOTE:** do *not* forget to add the `kotlinx` repository when using `coroutines` or `serialization`

### Forks

Jitpack.io also allows to build from `fuel` forks. If a fork's username is `$yourname`,

* adjust `group` to `com.github.$yourName.fuel`
* and look for `version` on `https://jitpack.io/#$yourName/Fuel`

## Quick start

Fuel requests can be made on the `Fuel` namespace object, any `FuelManager` or using one of the `String` extension methods. If you specify a callback the call is `async`, if you don't it's `blocking`.

#### Async Usage Example

```kotlin
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.result.Result

fun main(args: Array<String>) {

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

    httpAsync.join()
}
```

#### Blocking Usage Example

```kotlin
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.result.Result;

fun main(args: Array<String>) {

    val (request, response, result) = "https://httpbin.org/get"
        .httpGet()
        .responseString()

    when (result) {
        is Result.Failure -> {
            val ex = result.getException()
            println(ex)
        }
        is Result.Success -> {
            val data = result.get()
            println(data)
        }
    }

}

// You can also use Fuel.get("https://httpbin.org/get").responseString { ... }
// You can also use FuelManager.instance.get("...").responseString { ... }
```

`Fuel` and the extension methods use the `FuelManager.instance` under the hood. You can use this FuelManager to change the default behaviour of all requests:

```kotlin
FuelManager.instance.basePath = "https://httpbin.org"

"/get"
  .httpGet()
  .responseString { request, response, result -> /*...*/ }
// This is a GET request to "https://httpbin.org/get"
```

## Detailed usage

Check each of the packages documentations or the Wiki for more features, usages and examples. Are you looking for basic usage on how to set headers, authentication, request bodies and more? [`fuel`: Basic usage](/documentation/core/fuel) is all you need.

### Basic functionality

* [`fuel`: Basic usage](/documentation/core/fuel)
* [`fuel-android`: Android usage](/documentation/support/fuel-android)
* [`fuel-coroutines`: Execution with coroutines](/documentation/support/fuel-coroutines)

### Responses

* [`fuel-livedata`: Responses as LiveData](/documentation/support/fuel-livedata)
* [`fuel-reactor`: Responses as Mono](/documentation/support/fuel-reactor)
* [`fuel-rxjava`: Responses as Single](/documentation/support/fuel-rxjava)

### (De)serialization

* [`fuel-forge`: Deserialization with Forge](/documentation/deserialization/fuel-forge)
* [`fuel-gson`: (De)serialization with Gson](/documentation/deserialization/fuel-gson)
* [`fuel-jackson`: Deserialization with Jackson](/documentation/deserialization/fuel-jackson)
* [`fuel-json`: Deserialization with Json](/documentation/deserialization/fuel-json)
* [`fuel-kotlinx-serialization`: (De)serialization with KotlinX Serialization](/documentation/deserialization/fuel-kotlinx-serialization)
* [`fuel-moshi`: Deserialization with Moshi](/documentation/deserialization/fuel-moshi)

### Utility

* [`fuel-stetho` : Debugging bridge for Android with Stetho](https://github.com/kittinunf/fuel/blob/master/fuel-stetho/README.md)

## Other libraries

If you like Fuel, you might also like other libraries of mine;

* [Result](https://github.com/kittinunf/Result) - The modelling for success/failure of operations in Kotlin
* [Fuse](https://github.com/kittinunf/Fuse) - A simple generic LRU memory/disk cache for Android written in Kotlin
* [Forge](https://github.com/kittinunf/Forge) - Functional style JSON parsing written in Kotlin
* [ReactiveAndroid](https://github.com/kittinunf/ReactiveAndroid) - Reactive events and properties with RxJava for Android SDK

## Credits

Fuel is brought to you by [contributors](https://github.com/kittinunf/Fuel/graphs/contributors).

## Licenses

Fuel is released under the [MIT](https://opensource.org/licenses/MIT) license.


# Fuel

The core package for [`Fuel`](/documentation). The documentation outlined here touches most subjects and functions but is not exhaustive.

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `Fuel` with `Maven` and `Gradle`. The core package has the following dependencies:

* Kotlin - [![Kotlin](https://img.shields.io/badge/Kotlin-1.3.30-blue.svg)](https://kotlinlang.org)

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
```

## Usage

### Making Requests

You can make requests using functions on `Fuel`, a `FuelManager` instance or the string extensions.

```kotlin
Fuel.get("https://httpbin.org/get")
    .response { request, response, result ->
      println(request)
      println(response)
      val (bytes, error) = result
      if (bytes != null) {
        println("[response bytes] ${String(bytes)}")
      }
  }

/*
 * --> GET https://httpbin.org/get
 * "Body : (empty)"
 * "Headers : (0)"
 *

 * <-- 200 (https://httpbin.org/get)
 * Response : OK
 * Length : 268
 * Body : ({
 *   "args": {},
 *   "headers": {
 *     "Accept": "text/html, image/gif, image/jpeg, *; q=.2, *\/*; q=.2",
 *     "Connection": "close",
 *     "Host": "httpbin.org",
 *     "User-Agent": "Java/1.8.0_172"
 *   },
 *   "origin": "123.456.789.123",
 *   "url": "https://httpbin.org/get"
 * })
 * Headers : (8)
 * Connection : keep-alive
 * Date : Thu, 15 Nov 2018 00:47:50 GMT
 * Access-Control-Allow-Origin : *
 * Server : gunicorn/19.9.0
 * Content-Type : application/json
 * Content-Length : 268
 * Access-Control-Allow-Credentials : true
 * Via : 1.1 vegur

 * [response bytes] {
 *   "args": {},
 *   "headers": {
 *     "Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
 *     "Connection": "close",
 *     "Host": "httpbin.org",
 *     "User-Agent": "Java/1.8.0_172"
 *   },
 *   "origin": "123.456.789.123",
 *   "url": "https://httpbin.org/get"
 * }
 */
```

The extensions and functions made available by the core package are listed here:

| Fuel Method      | String extension                          | `Fuel`/`FuelManager` method                                    |
| ---------------- | ----------------------------------------- | -------------------------------------------------------------- |
| `Method.GET`     | `"https://httpbin.org/get".httpGet()`     | `Fuel.get("https://httpbin.org/get")`                          |
| `Method.POST`    | `"https://httpbin.org/post".httpPost()`   | `Fuel.post("https://httpbin.org/post")`                        |
| `Method.PUT`     | `"https://httpbin.org/put".httpPut()`     | `Fuel.put("https://httpbin.org/put")`                          |
| `Method.PATCH`   | `"https://httpbin.org/patch".httpPatch()` | `Fuel.patch("https://httpbin.org/patch")`                      |
| `Method.HEAD`    | `"https://httpbin.org/get".httpHead()`    | `Fuel.head("https://httpbin.org/get")`                         |
| `Method.OPTIONS` | *not supported*                           | `Fuel.request(Method.OPTIONS, "https://httpbin.org/anything")` |
| `Method.TRACE`   | *not supported*                           | `Fuel.request(Method.TRACE, "https://httpbin.org/anything")`   |
| `Method.CONNECT` | *not supported*                           | *not supported*                                                |

#### About `PATCH` requests

The default `client` is [`HttpClient`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/com/github/kittinunf/fuel/toolbox/HttpClient.kt) which is a thin wrapper over [`java.net.HttpUrlConnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html). [`java.net.HttpUrlConnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html) does not support a [`PATCH`](https://download.java.net/jdk7/archive/b123/docs/api/java/net/HttpURLConnection.html#setRequestMethod\(java.lang.String\)) method. [`HttpClient`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/com/github/kittinunf/fuel/toolbox/HttpClient.kt) converts `PATCH` requests to a `POST` request and adds a `X-HTTP-Method-Override: PATCH` header. While this is a semi-standard industry practice not all APIs are configured to accept this header by default.

```kotlin
Fuel.patch("https://httpbin.org/patch")
    .also { println(it) }
    .response { result -> }

/* --> PATCH https://httpbin.org/post
 * "Body : (empty)"
 * "Headers : (1)"
 * Content-Type : application/x-www-form-urlencoded
 */

// What is actually sent to the server

/* --> POST (https://httpbin.org/post)
 * "Body" : (empty)
 * "Headers : (3)"
 * Accept-Encoding : compress;q=0.5, gzip;q=1.0
 * Content-Type : application/x-www-form-urlencoded
 * X-HTTP-Method-Override : PATCH
 */
```

**Experimental**

As of version `1.16.x` you can **opt-in** to forcing a HTTP Method on the [`java.net.HttpUrlConnnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html) instance using reflection.

```kotlin
FuelManager.instance.forceMethods = true

Fuel.patch("https://httpbin.org/patch")
    .also { println(it) }
    .response { result -> }

/* --> PATCH (https://httpbin.org/patch)
 * "Body" : (empty)
 * "Headers : (3)"
 * Accept-Encoding : compress;q=0.5, gzip;q=1.0
 * Content-Type : application/x-www-form-urlencoded
 */
```

#### About `CONNECT` request

Connect is not supported by the Java JVM via the regular HTTP clients, and is therefore not supported.

### Adding `Parameters`

All the `String` extensions listed above, as well as the `Fuel` and `FuelManager` calls accept a parameter `parameters: Parameters`.

* URL encoded style for `GET` and `DELETE` request

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

  ```kotlin
  Fuel.delete("https://httpbin.org/delete", listOf("foo" to "foo", "bar" to "bar"))
      .url
  // https://httpbin.org/delete?foo=foo&bar=bar
  ```
* Support `x-www-form-urlencoded` for `PUT`, `POST` and `PATCH`

  ```kotlin
  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"
  ```

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

  // https://httpbin.org/put
  // "foo=foo&bar=bar"
  ```

#### `Parameters` with `Body`

If a request already has a body, the parameters are url-encoded instead. You can remove the handling of parameter encoding by removing the default `ParameterEncoder` request interceptor from your `FuelManager`.

#### `Parameters` with `multipart/form-data`

The `UploadRequest` handles encoding parameters in the body. Therefore by default, parameter encoding is ignored by `ParameterEncoder` if the content type is `multipart/form-data`.

#### `Parameters` with empty, array, list or null values

All requests can have parameters, regardless of the method.

* a list is encoded as `key[]=value1&key[]=value2&...`
* an array is encoded as `key[]=value1&key[]=value2&...`
* an empty string value is encoded as `key`
* a null value is removed

### Adding `Request` body

Bodies are formed from generic streams, but there are helpers to set it from values that can be turned into streams. It is important to know that, by default, the streams are **NOT** read into memory until the `Request` is sent. However, if you pass in an in-memory value such as a `ByteArray` or `String`, `Fuel` uses `RepeatableBody`, which are kept into memory until the `Request` is dereferenced.

When you're using the default `Client`, bodies are supported for:

* `POST`
* `PUT`
* `PATCH` (actually a `POST`, as noted above)
* `DELETE`

There are several functions to set a `Body` for the request. If you are looking for a `multipart/form-data` upload request, checkout the `UploadRequest` feature.

```kotlin
Fuel.post("https://httpbin.org/post")
    .body("My Post Body")
    .also { println(it) }
    .response { result -> }

/* --> POST https://httpbin.org/post
 * "Body : My Post Body"
 * "Headers : (1)"
 * Content-Type : application/x-www-form-urlencoded
 */
```

#### Use `application/json`

If you don't want to set the `application/json` header, you can use `.jsonBody(value: String)` extension to automatically do this for you.

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

/* --> POST https://httpbin.org/post
 * "Body : { "foo" : "bar" }"
 * "Headers : (1)"
 * Content-Type : application/json
 */
```

#### from `String`

```kotlin
Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body("my body is plain")
    .also { println(it) }
    .response { result -> }

/* --> POST https://httpbin.org/post
 * "Body : my body is plain"
 * "Headers : (1)"
 * Content-Type : text/plain
 */
```

#### from a `File`

```kotlin
Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body(File("lipsum.txt"))
    .also { println(it) }
    .response { result -> }

/* --> POST https://httpbin.org/post
 * "Body : Lorem ipsum dolor sit amet, consectetur adipiscing elit."
 * "Headers : (1)"
 * Content-Type : text/plain
 */
```

#### from a `InputStream`

```kotlin
val stream = ByteArrayInputStream("source-string-from-string".toByteArray())

Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body(stream)
    .also { println(it) }
    .response { result -> }

/* --> POST https://httpbin.org/post
 * "Body : source-string-from-string"
 * "Headers : (1)"
 * Content-Type : text/plain
 */
```

#### from a `lazy` source (`InputStream`)

Fuel always reads the body lazily, which means you can also provide a callback that will return a stream. This is also known as a `BodyCallback`:

```kotlin
val produceStream = { ByteArrayInputStream("source-string-from-string".toByteArray()) }

Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body(produceStream)
    .also { println(it) }
    .response { result -> }

/* --> POST https://httpbin.org/post
 * "Body : source-string-from-string"
 * "Headers : (1)"
 * Content-Type : text/plain
 */
```

#### Using automatic body redirection

The default redirection interceptor only forwards `RepeatableBody`, and only if the status code is 307 or 308, as per the RFCs. In order to use a `RepeatableBody`, pass in a `String` or `ByteArray` as body, or explicitely set `repeatable = true` for the `fun body(...)` call.

**NOTE** this loads the *entire* body into memory, and therefore is not suited for large bodies.

### Adding `Headers`

There are many ways to set, overwrite, remove and append headers. For your convenience, internally used and common header names are attached to the `Headers` companion and can be accessed (e.g. `Headers.CONTENT_TYPE`, `Headers.ACCEPT`, ...).

The most common ones are mentioned here:

#### Reading `HeaderValues`

| call                     | arguments        | action                                                                  |
| ------------------------ | ---------------- | ----------------------------------------------------------------------- |
| `request[header]`        | `header: String` | Get the current values of the header, after normalisation of the header |
| `request.header(header)` | `header: String` | Get the current values                                                  |

#### (Over)writing `HeaderValues`

| call                                        | arguments                                 | action                                                                                   |
| ------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------- |
| `request[header] = values`                  | `header: String`, `values: Collection<*>` | Set the values of the header, overriding what's there, after normalisation of the header |
| `request[header] = value`                   | `header: String`, `value: Any`            | Set the value of the header, overriding what's there, after normalisation of the header  |
| `request.header(map)`                       | `map: Map<String, Any>`                   | Replace the headers with the map provided                                                |
| `request.header(pair, pair, ...)`           | `vararg pairs: Pair<String, Any>`         | Replace the headers with the pairs provided                                              |
| `request.header(header, values)`            | `header: String, values: Collection<*>`   | Replace the header with the provided values                                              |
| `request.header(header, value)`             | `header: String, value: Any`              | Replace the header with the provided value                                               |
| `request.header(header, value, value, ...)` | `header: String, vararg values: Any`      | Replace the header with the provided values                                              |

#### Appending `HeaderValues`

| call                                              | arguments                            | action                                                                     |
| ------------------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------- |
| `request.appendHeader(pair, pair, ...)`           | `vararg pairs: Pair<String, Any>`    | Append each pair, using the key as header name and value as header content |
| `request.appendHeader(header, value)`             | `header: String, value: Any`         | Appends the value to the header or sets it if there was none yet           |
| `request.appendHeader(header, value, value, ...)` | `header: String, vararg values: Any` | Appends the value to the header or sets it if there was none yet           |

Note that headers which by the RFC may only have one value are always overwritten, such as `Content-Type`.

#### `FuelManager` base headers vs. `Request` headers

The `baseHeaders` set through a `FuelManager` are only applied to a `Request` if that request does **not** have that specific header set yet. There is no appending logic. If you set a header it will overwrite the base value.

#### `Client` headers vs. `Request` headers

Any `Client` can add, remove or transform `HeaderValues` before it sends the `Request` or after it receives the `Response`. The default `Client` for example sets `TE` values.

#### `HeaderValues` values are `List`

Even though some headers can only be set once (and will overwrite even when you try to append), the internal structure is always a list. Before a `Request` is made, the default `Client` collapses the multiple values, if allowed by the RFCs, into a single header value delimited by a separator for that header. Headers that can only be set once will use the last value by default and ignore earlier set values.

### Adding Authentication

Authentication can be added to a `Request` using the `.authentication()` feature. By default, `authentication` is passed on when using the default `redirectResponseInterceptor` (which is enabled by default), unless it is redirecting to a different host. You can remove this behaviour by implementing your own redirection logic.

> When you call `.authentication()`, a few extra functions are available. If you call a regular function (e.g. `.header()`) the extra functions are no longer available, but you can safely call `.authentication()` again without losing any previous calls.

* *Basic* authentication

```kotlin
val username = "username"
val password = "abcd1234"

Fuel.get("https://httpbin.org/basic-auth/$user/$password")
    .authentication()
    .basic(username, password)
    .response { result -> }
```

* *Bearer* authentication

```kotlin
val token = "mytoken"

Fuel.get("https://httpbin.org/bearer")
    .authentication()
    .bearer(token)
    .response { result -> }
```

* Any authentication using a header

```kotlin
Fuel.get("https://httpbin.org/anything")
    .header(Headers.AUTHORIZATION, "Custom secret")
    .response { result -> }
```

### Adding Progress callbacks

Any request supports `Progress` callbacks when uploading or downloading a body; the `Connection` header does not support progress (which is the only thing that is sent if there are no bodies). You can have as many progress handlers of each type as you like.

#### Request progress

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

#### Response progress

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

#### Throttling progress output

Often the progress of a download will be shown as [notification](https://developer.android.com/guide/topics/ui/notifiers/notifications). Since Android Nougat (API 24), only 10 notification updates per second per app are allowed. Anything more than that will result in a log error like `E/NotificationService: Package enqueue rate is 10.062265. Shedding events. package=...`.

It is the responsibility of the library user *– not of fuel –* to remedy this limit. A simple solution could look like this:

```kotlin
var lastUpdate = 0L
Fuel.get("/get")
   .progress { readBytes, totalBytes ->
      // allow 2 updates/second max - more than 10/second will be blocked
      if (System.currentTimeMillis() - lastUpdate > 500) {
         lastUpdate = System.currentTimeMillis()
         val progress = readBytes.toFloat() / totalBytes.toFloat() * 100
         myNotificationHelper.notifyDownloadProgress(progress)
      }
   }
   .response { result -> }
```

#### Why does totalBytes increase?

Not all source `Body` or `Response` `Body` report their total size. If the size is not known, the current size will be reported. This means that you will constantly get an increasing amount of totalBytes that equals readBytes.

### Using `multipart/form-data` (`UploadRequest`)

Fuel supports multipart uploads using the `.upload()` feature. You can turn *any* `Request` into a upload request by calling `.upload()` or call `.upload(method = Method.POST)` directly onto `Fuel` / `FuelManager`.

> When you call `.upload()`, a few extra functions are available. If you call a regular function (e.g. `.header()`) the extra functions are no longer available, but you can safely call `.upload()` again without losing any previous calls.

| method                      | arguments                                  | action                               |
| --------------------------- | ------------------------------------------ | ------------------------------------ |
| `request.add { }`           | `varargs dataparts: (Request) -> DataPart` | Add one or multiple DataParts lazily |
| `request.add()`             | `varargs dataparts: DataPart`              | Add one or multiple DataParts        |
| `request.progress(handler)` | `hander: ProgressCallback`                 | Add a `requestProgress` handler      |

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

#### `DataPart` from `File`

In order to add `DataPart`s that are sources from a `File`, you can use `FileDataPart`, which takes a `file: File`. There are some sane defaults for the field name `name: String`, and remote file name `filename: String`, as well as the `Content-Type` and `Content-Disposition` fields, but you can override them.

In order to receive a list of files, for example in the field `files`, use the array notation:

```kotlin
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 -> }
```

Sending multiple files in a single datapart is *not* supported as it's deprecated by the multipart/form-data RFCs, but to simulate this behaviour, give the same `name` to multiple parts.

You can use the convenience constructors `FileDataPart.from(directory: , filename: , ...args)` to create a `FileDataPart` from `String` arguments.

#### `DataPart` from inline content

Sometimes you have some content inline that you want to turn into a `DataPart`. You can do this with `InlineDataPart`:

```kotlin
Fuel.upload("/post")
    .add(
        FileDataPart(File("myfile.json"), name = "file", filename="contents.json"),
        InlineDataPart(myInlineContent, name = "metadata", filename="metadata.json", contentType = "application/json")
    )
    .response { result -> }
```

A `filename` is not mandatory and is empty by default; the `contentType` is `text/plain` by default.

#### `DataPart` from `InputStream` (formely `Blob`)

You can also add dataparts from arbitrary `InputStream`s, which you can do using `BlobDataPart`:

```kotlin
Fuel.upload("/post")
    .add(
        FileDataPart(File("myfile.json"), name = "file", filename="contents.json"),
        BlobDataPart(someInputStream, name = "metadata", filename="metadata.json", contentType = "application/json", contentLength = 555)
    )
    .response { result -> }
```

If you don't set the `contentLength` to a positive integer, your entire `Request` `Content-Length` will be undeterminable and the default `HttpClient` will switch to chunked streaming mode with an arbitrary stream buffer size.

#### Multipart request without a file

Simply don't call `add`. The parameters are encoded as parts!

```kotlin
val formData = listOf("Email" to "mail@example.com", "Name" to "Joe Smith" )

Fuel.upload("/post", param = formData)
    .response { result -> }
```

### Getting a Response

As mentioned before, you can use `Fuel` both synchronously and a-synchronously, with support for coroutines.

#### Blocking responses

By default, there are three response functions to get a request synchronously:

| function                       | arguments                       | result                        |
| ------------------------------ | ------------------------------- | ----------------------------- |
| `response()`                   | *none*                          | `ResponseResultOf<ByteArray>` |
| `responseString(charset)`      | `charset: Charset`              | `ResponseResultOf<String>`    |
| `responseObject(deserializer)` | `deserializer: Deserializer<U>` | `ResponseResultOf<U>`         |

The default charset is `UTF-8`. If you want to implement your own deserializers, scroll down to advanced usage.

#### Async responses

Add a handler to a blocking function, to make it asynchronous:

| function                                   | arguments                                      | result               |
| ------------------------------------------ | ---------------------------------------------- | -------------------- |
| `response() { handler }`                   | `handler: Handler`                             | `CancellableRequest` |
| `responseString(charset) { handler }`      | `charset: Charset, handler: Handler`           | `CancellableRequest` |
| `responseObject(deserializer) { handler }` | `deserializer: Deserializer, handler: Handler` | `CancellableRequest` |

The default charset is `UTF-8`. If you want to implement your own deserializers, scroll down to advanced usage.

#### Suspended responses

The core package has limited support for coroutines:

| function                            | arguments                       | result                 |
| ----------------------------------- | ------------------------------- | ---------------------- |
| `await(deserializer)`               | `deserializer: Deserializer<U>` | `U`                    |
| `awaitResult(deserializer)`         | `deserializer: Deserializer<U>` | `Result<U, FuelError>` |
| `awaitResponse(deserializer)`       | `deserializer: Deserializer<U>` | `ResponseOf<U>`        |
| `awaitResponseResult(deserializer)` | `deserializer: Deserializer<U>` | `ResponseResultOf<U>`  |

When using other packages such as `fuel-coroutines`, more response/await functions are available.

#### Response types

* The `ResponseResultOf<U>` type is a `Triple` of the `Request`, `Response` and a `Result<U, FuelError>`
* The `ResponseOf<U>` type is a `Triple` of the `Request`, `Response` and a `U`; errors are thrown
* The `Result<U, FuelError>` type is a non-throwing wrapper around `U`
* The `U` type doesn't wrap anything; errors are thrown

#### Handler types

When defining a handler, you can use one of the following for all `responseXXX` functions that accept a `Handler`:

| type                       | handler fns | arguments | description                                                                               |
| -------------------------- | ----------- | --------- | ----------------------------------------------------------------------------------------- |
| `Handler<T>`               | 2           | 1         | calls `success` with an instance of `T` or `failure` on errors                            |
| `ResponseHandler<T>`       | 2           | 3         | calls `success` with `Request`, `Response` and an instance of `T`, or `failure` or errors |
| `ResultHandler<T>`         | 1           | 1         | invokes the function with `Result<T, FuelError>`                                          |
| `ResponseResultHandler<T>` | 1           | 3         | invokes the function with `Request` `Response` and `Result<T, FuelError>`                 |

This means that you can either choose to unwrap the `Result` yourself using a `ResultHandler` or `ResponseResultHandler`, or define dedicated callbacks in case of success or failure.

#### Dealing with `Result<T, FuelError>`

[Result](https://github.com/kittinunf/Result) is a functional style data structure that represents data that contains result of *Success* or *Failure* but not both. It represents the result of an action that can be success (with result) or error.

Working with result is easy:

* You can call \[`fold`] and define a tranformation function for both cases that results in the same return type,
* \[`destructure`] as `(data, error) = result` because it is just a [data class](https://kotlinlang.org/docs/reference/data-classes.html) or
* use `when` checking whether it is `Result.Success` or `Result.Failure`

#### Download response to output (`File` or `OutputStream`)

Fuel supports downloading the request `Body` to a file using the `.download()` feature. You can turn *any* `Request` into a download request by calling `.download()` or call `.download(method = Method.GET)` directly onto `Fuel` / `FuelManager`.

> When you call `.download()`, a few extra functions are available. If you call a regular function (e.g. `.header()`) the extra functions are no longer available, but you can safely call `.download()` again without losing any previous calls.

| method                          | arguments                                                      | action                                                    |
| ------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------- |
| `request.fileDestination { }`   | `(Response, Request) -> File`                                  | Set the destination file callback where to store the data |
| `request.streamDestination { }` | `(Response, Request) -> Pair<OutputStream, () -> InputStream>` | Set the destination file callback where to store the data |
| `request.progress(handler)`     | `hander: ProgressCallback`                                     | Add a `responseProgress` handler                          |

```kotlin
Fuel.download("https://httpbin.org/bytes/32768")
    .fileDestination { response, url -> File.createTempFile("temp", ".tmp") }
    .progress { readBytes, totalBytes ->
        val progress = readBytes.toFloat() / totalBytes.toFloat() * 100
        println("Bytes downloaded $readBytes / $totalBytes ($progress %)")
    }
    .response { result -> }
```

The `stream` variant expects your callback to provide a `Pair` with both the `OutputStream` to write too, as well as a callback that gives an `InputStream`, or raises an error.

* The `OutputStream` is *always* closed after the body has been written. Make sure you wrap whatever functionality you need on top of the stream and don't rely on the stream to remain open.
* The `() -> InputStream` replaces the body after the current body has been written to the `OutputStream`. It is used to make sure you can *also* retrieve the body via the `response` / `await` method results. If you don't want the body to be readable after downloading it, you have to do two things:
  * use an `EmptyDeserializer` with `await(deserializer)` or one of the `response(deserializer)` variants
  * provide an `InputStream` callback that `throws` or returns an empty `InputStream`.

For downloading larger files it is good to use `request.streamDestination { }` instead of `request.fileDestination { }`

```kotlin
val outputStream = FileOutputStream(File(filePath))

Fuel.download("https://httpbin.org/bytes/32768")
    .streamDestination { response, request -> Pair(outputStream, { request.body.toStream() }) }
    .progress { readBytes, totalBytes ->
        val progress = readBytes.toFloat() / totalBytes.toFloat() * 100
        println("Bytes downloaded $readBytes / $totalBytes ($progress %)")
    }
    .response { result -> 

        result.fold(

                success = {
                    
                },

                failure = {
                    
                }
        )
    }
```

### Cancel an async `Request`

The `response` functions called with a `handler` are async and return a `CancellableRequest`. These requests expose a few extra functions that can be used to control the `Future` that should resolve a response:

```kotlin
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
```

If you can't get hold of the `CancellableRequest` because, for example, you are adding this logic in an `Interceptor`, a generic `Queue`, or a `ProgressCallback`, you can call `tryCancel()` which returns true if it was cancelled and false otherwise. At this moment `blocking` requests *can not* be cancelled.

## Advanced Configuration

### Request Configuration

* `baseHeaders` is to manage common HTTP header pairs in format of `Map<String, String>`.
  * The base headers are only applied if the request does not have those headers set.

```kotlin
FuelManager.instance.baseHeaders = mapOf("Device" to "Android")
```

* `Headers` can be added to a request via various methods including

```kotlin
fun header(name: String, value: Any): Request = request.header("foo", "a")
fun header(pairs: Map<String, Any>): Request = request.header(mapOf("foo" to "a"))
fun header(vararg pairs: Pair<String, Any>): Request = request.header("foo" to "a")

operator fun set(header: String, value: Collection<Any>): Request = request["foo"] = listOf("a", "b")
operator fun set(header: String, value: Any): Request = request["foo"] = "a"
```

* By default, all subsequent calls overwrite earlier calls, but you may use the `appendHeader` variant to append values to existing values.
  * In earlier versions (1.x.y), a `mapOf` overwrote, and `varargs pair` did not, but this was confusing. In 2.0, this issue has been fixed and improved so it works as expected.

```kotlin
fun appendHeader(header: String, value: Any): Request
fun appendHeader(header: String, vararg values: Any): Request
fun appendHeader(vararg pairs: Pair<String, Any>): Request
```

* Some of the HTTP headers are defined under `Headers.Companion` and can be used instead of literal strings. This is an encouraged way to configure your header in 2.x.y.

```kotlin
Fuel.post("/my-post-path")
   .header(Headers.ACCEPT, "text/html, */*; q=0.1")
   .header(Headers.CONTENT_TYPE, "image/png")
   .header(Headers.COOKIE to "basic=very")
   .appendHeader(Headers.COOKIE to "value_1=foo", Headers.COOKIE to "value_2=bar", Headers.ACCEPT to "application/json")
   .appendHeader("MyFoo" to "bar", "MyFoo" to "baz")
   .response { /*...*/ }

// => request with:
//    Headers:
//      Accept: "text/html, */*; q=0.1, application/json"
//      Content-Type: "image/png"
//      Cookie: "basic=very; value_1=foo; value_2=bar"
//      MyFoo: "bar, baz"
```

### Response Deserialization

* Fuel provides built-in support for response deserialization. Here is how one might want to use Fuel together with [Gson](https://github.com/google/gson)

```kotlin
//User Model
data class User(val firstName: String = "",
                val lastName: String = "") {

    //User Deserializer
    class Deserializer : ResponseDeserializable<User> {
        override fun deserialize(content: String) = Gson().fromJson(content, User::class.java)
    }

}

//Use httpGet extension
"https://www.example.com/user/1".httpGet().responseObject(User.Deserializer()) { req, res, result ->
    //result is of type Result<User, Exception>
    val (user, err) = result

    println(user.firstName)
    println(user.lastName)
}
```

* There are 4 methods to support response deserialization depending on your needs (also depending on JSON parsing library of your choice), and you are required to implement only one of them.

```kotlin
fun deserialize(bytes: ByteArray): T?
fun deserialize(inputStream: InputStream): T?
fun deserialize(reader: Reader): T?
fun deserialize(content: String): T?
```

* Another example may be parsing a website that is not UTF-8. By default, Fuel serializes text as UTF-8, we need to define our deserializer as such

```kotlin
object Windows1255StringDeserializer : ResponseDeserializable<String> {
    override fun deserialize(bytes: ByteArray): String {
        return String(bytes, "windows-1255")
    }
}
```

### Detail Configuration

* Use singleton `FuelManager.instance` to manage global configurations.
* Create separate managers using `FuelManager()`
* `basePath` is used to manage common root path. Great usage is for your static API endpoint.

```kotlin
FuelManager.instance.basePath = "https://httpbin.org"

// Later
Fuel.get("/get").response { request, response, result ->
    //make request to https://httpbin.org/get because Fuel.{get|post|put|delete} use FuelManager.instance to make HTTP request
}
```

* `baseParams` is used to manage common `key=value` query param, which will be automatically included in all of your subsequent requests in format of `Parameters` (`Any` is converted to `String` by `toString()` method)

```kotlin
FuelManager.instance.baseParams = listOf("api_key" to "1234567890")

// Later
Fuel.get("/get").response { request, response, result ->
    //make request to https://httpbin.org/get?api_key=1234567890
}
```

* `client` is a raw HTTP client driver. Generally, it is responsible to make [`Request`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/fuel/core/Request.kt) into [`Response`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/fuel/core/Response.kt). Default is [`HttpClient`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/fuel/toolbox/HttpClient.kt) which is a thin wrapper over [`java.net.HttpUrlConnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html). You could use any httpClient of your choice by conforming to [`client`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/com/github/kittinunf/fuel/core/Client.kt) protocol, and set back to `FuelManager.instance` to kick off the effect.
* `keyStore` is configurable by user. By default it is `null`.
* `socketFactory` can be supplied by user. If `keyStore` is not null, `socketFactory` will be derived from it.
* `hostnameVerifier` is configurable by user. By default, it uses `HttpsURLConnection.getDefaultHostnameVerifier()`.
* `requestInterceptors` `responseInterceptors` is a side-effect to add to `Request` and/or `Response` objects.
  * For example, one might wanna print cUrlString style for every request that hits server in DEBUG mode.

```kotlin
val manager = FuelManager()
if (BUILD_DEBUG) {
    manager.addRequestInterceptor(cUrlLoggingRequestInterceptor())
}

// Usage
val (request, response, result) = manager.request(Method.GET, "https://httpbin.org/get").response() //it will print curl -i -H "Accept-Encoding:compress;q=0.5, gzip;q=1.0" "https://httpbin.org/get"
```

* Another example is that you might wanna add data into your Database, you can achieve that with providing `responseInterceptors` such as

```kotlin
inline fun <reified T> DbResponseInterceptor() =
    { next: (Request, Response) -> Response ->
        { req: Request, res: Response ->
            val db = DB.getInstance()
            val instance = Parser.getInstance().parse(res.data, T::class)
            db.transaction {
                it.copyToDB(instance)
            }
            next(req, res)
        }
    }

manager.addResponseInterceptor(DBResponseInterceptor<Dog>)
manager.request(Method.GET, "https://www.example.com/api/dog/1").response() // Db interceptor will be called to intercept data and save into Database of your choice
```

### Routing Support

In order to organize better your network stack FuelRouting interface allows you to easily setup a Router design pattern.

```kotlin
// Router Definition
sealed class WeatherApi: FuelRouting {

    override val basePath = "https://www.metaweather.com"

    class weatherFor(val location: String): WeatherApi() {}

    override val method: Method
        get() {
            when(this) {
                is weatherFor -> return Method.GET
            }
        }

    override val path: String
        get() {
            return when(this) {
                is weatherFor -> "/api/location/search/"
            }
        }

    override val params: Parameters?
        get() {
            return when(this) {
                is weatherFor -> listOf("query" to this.location)
            }
        }

    override val headers: Map<String, String>?
        get() {
            return null
        }

}

// Usage
Fuel.request(WeatherApi.weatherFor("london"))
    .responseJson { request, response, result ->
        result.fold(success = { json ->
            Log.d("Success", json.array().toString())
        }, failure = { error ->
            Log.e("Failure", error.toString())
        })
    }
```


# Android

The android package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-android` with `Maven` and `Gradle`. The android package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Android SDK: 19+

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-android:<latest-version>'
```

## Usage

The `fuel` core package automatically uses the `AndroidEnvironment` from the `fuel-android` package to redirect callbacks to the main looper thread.

### Making Requests

It is the same with core package, so refer on core documentation at [here](/documentation/core/fuel)


# Coroutines

The coroutines extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-coroutines` with `Maven` and `Gradle`. The coroutines package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* KotlinX Coroutines: 1.1.1

### Gradle

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-coroutines:<latest-version>'
```

### Maven

```markup
<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel</artifactId>
    <version>[LATEST_VERSION]</version>
</dependency>

<dependency>
    <groupId>com.github.kittinunf.fuel</groupId>
    <artifactId>fuel-coroutines</artifactId>
    <version>[LATEST_VERSION]</version>
</dependency>
```

## Usage

Coroutines module provides extension functions to wrap a response inside a coroutine and handle its result. The coroutines-based API provides equivalent methods to the standard API (e.g: `responseString()` in coroutines is `awaitStringResponseResult()`).

```kotlin
runBlocking {
    val (request, response, result) = Fuel.get("https://httpbin.org/ip").awaitStringResponseResult()

    result.fold(
        { data -> println(data) /* "{"origin":"127.0.0.1"}" */ },
        { error -> println("An error of type ${error.exception} happened: ${error.message}") }
    )
}
```

There are functions to handle `Result` object directly too.

```kotlin
runBlocking {
    Fuel.get("https://httpbin.org/ip")
        .awaitStringResponseResult()
        .fold(
            { data -> println(data) /* "{"origin":"127.0.0.1"}" */ },
            { error -> println("An error of type ${error.exception} happened: ${error.message}") }
        )
}
```

It also provides useful methods to retrieve the `ByteArray`,`String` or `Object` directly. The difference with these implementations is that they throw exception instead of returning it wrapped a `FuelError` instance.

```kotlin
runBlocking {
    try {
        println(Fuel.get("https://httpbin.org/ip").awaitString()) // "{"origin":"127.0.0.1"}"
    } catch(exception: Exception) {
        println("A network request exception was thrown: ${exception.message}")
    }
}
```

Handling objects other than `String` (`awaitStringResponseResult()`) or `ByteArray` (`awaitByteArrayResponseResult()`) can be done using `awaitObject`, `awaitObjectResult` or `awaitObjectResponseResult`.

```kotlin
data class Ip(val origin: String)

object IpDeserializer : ResponseDeserializable<Ip> {
    override fun deserialize(content: String) =
        jacksonObjectMapper().readValue<Ip>(content)
}
```

```kotlin
runBlocking {
    Fuel.get("https://httpbin.org/ip")
        .awaitObjectResult(IpDeserializer)
        .fold(
            { data -> println(data.origin) /* 127.0.0.1 */ },
            { error -> println("An error of type ${error.exception} happened: ${error.message}") }
        )
}
```

```kotlin
runBlocking {
    try {
        val data = Fuel.get("https://httpbin.org/ip").awaitObject(IpDeserializer)
        println(data.origin) // 127.0.0.1
    } catch (exception: Exception) {
        when (exception){
            is HttpException -> println("A network request exception was thrown: ${exception.message}")
            is JsonMappingException -> println("A serialization/deserialization exception was thrown: ${exception.message}")
            else -> println("An exception [${exception.javaClass.simpleName}\"] was thrown")
        }
    }
}
```


# AAC LiveData

The `LiveData` extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-livedata` with `Maven` and `Gradle`. The livedata package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* [AndroidX Livedata](https://developer.android.com/topic/libraries/architecture/livedata.html): 2.0.0

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-livedata:<latest-version>'
```

## Usage

See `FuelLiveData.kt`

### LiveData Response

* Fuel supports [LiveData](https://developer.android.com/topic/libraries/architecture/livedata.html)

  ```kotlin
  Fuel.get("www.example.com/get")
    .liveDataResponse()
    .observe(this) { /* do something */ }
  ```


# RxJava

The rxjava extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-rxjava` with `Maven` and `Gradle`. The rxjava package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* RxJava: 2.2.6

```groovy
compile 'com.github.kittinunf.fuel:fuel:<latest-version>'
compile 'com.github.kittinunf.fuel:fuel-rxjava:<latest-version>'
```

## Usage

See `RxFuel.kt`

### Responses

* Fuel supports [RxJava](https://github.com/ReactiveX/RxJava) right off the box.

  ```kotlin
    "https://www.example.com/photos/1".httpGet()
      .rxObject(Photo.Deserializer())
      .subscribe { /* do something */ }
  ```
* There are extensions over `Request` that provide RxJava 2.x `Single<Result<T, FuelError>>` as return type.

```kotlin
/**
 * Returns a reactive stream for a [Single] value response [ByteArray]
 *
 * @see rxBytes
 * @return [Single<T>] the [ByteArray] wrapped into a [Pair] and [Result]
 */
fun Request.rxResponse() = rxResponseSingle(ByteArrayDeserializer())
fun Request.rxResponsePair() = rxResponsePair(ByteArrayDeserializer())
fun Request.rxResponseTriple() = rxResponseTriple(ByteArrayDeserializer())

/**
 * Returns a reactive stream for a [Single] value response [String]
 *
 * @see rxString
 *
 * @param charset [Charset] the character set to deserialize with
 * @return [Single<Pair<Response, Result<String, FuelError>>>] the [String] wrapped into a [Pair] and [Result]
 */
fun Request.rxResponseString(charset: Charset = Charsets.UTF_8) = rxResponseSingle(StringDeserializer(charset))
fun Request.rxResponseStringPair(charset: Charset = Charsets.UTF_8) = rxResponsePair(StringDeserializer(charset))
fun Request.rxResponseStringTriple(charset: Charset = Charsets.UTF_8) = rxResponseTriple(StringDeserializer(charset))

/**
 * Returns a reactive stream for a [Single] value response object [T]
 *
 * @see rxObject
 *
 * @param deserializable [Deserializable<T>] something that can deserialize the [Response] to a [T]
 * @return [Single<Pair<Response, Result<T, FuelError>>>] the [T] wrapped into a [Pair] and [Result]
 */
fun <T : Any> Request.rxResponseObject(deserializable: Deserializable<T>) = rxResponseSingle(deserializable)
fun <T : Any> Request.rxResponseObjectPair(deserializable: Deserializable<T>) = rxResponsePair(deserializable)
fun <T : Any> Request.rxResponseObjectTriple(deserializable: Deserializable<T>) = rxResponseTriple(deserializable)

/**
 * Returns a reactive stream for a [Single] value response [ByteArray]
 *
 * @see rxResponse
 * @return [Single<Result<ByteArray, FuelError>>] the [ByteArray] wrapped into a [Result]
 */
fun Request.rxBytes() = rxResult(ByteArrayDeserializer())

/**
 * Returns a reactive stream for a [Single] value response [ByteArray]
 *
 * @see rxResponseString
 *
 * @param charset [Charset] the character set to deserialize with
 * @return [Single<Result<String, FuelError>>] the [String] wrapped into a [Result]
 */
fun Request.rxString(charset: Charset = Charsets.UTF_8) = rxResult(StringDeserializer(charset))

/**
 * Returns a reactive stream for a [Single] value response [T]
 *
 * @see rxResponseObject
 *
 * @param deserializable [Deserializable<T>] something that can deserialize the [Response] to a [T]
 * @return [Single<Result<T, FuelError>>] the [T] wrapped into a [Result]
 */
fun <T : Any> Request.rxObject(deserializable: Deserializable<T>) = rxResult(deserializable)
```


# Reactor

The reactor extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-reactor` with `Maven` and `Gradle`. The reactor package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Project Reactor: 3.2.2.RELEASE

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-reactor:<latest-version>'
```

## Usage

See `FuelReactor.kt`

### Responses

The Reactor module API provides functions starting with the prefix `mono` to handle instances of `Response`, `Result<T, FuelError>` and values directly (`String`, `ByteArray`, `Any`). All functions expose exceptions as `FuelError` instance.

**Data handling example**

```kotlin
Fuel.get("https://icanhazdadjoke.com")
    .header(Headers.ACCEPT to "text/plain")
    .monoString()
    .subscribe(::println)
```

**Error handling example**

```kotlin
data class Guest(val name: String)

object GuestMapper : ResponseDeserializable<Guest> {
    override fun deserialize(content: String) =
        jacksonObjectMapper().readValue<Guest>(content)
}

Fuel.get("/guestName").monoResultObject(GuestMapper)
    .map(Result<Guest, FuelError>::get)
    .map { (name) -> "Welcome to the party, $name!" }
    .onErrorReturn("I'm sorry, your name is not on the list.")
    .subscribe(::println)
```

**Response handling example**

```kotlin
FuelManager.instance.basePath = "https://httpbin.org"

Fuel.get("/status/404").monoResponse()
    .filter(Response::isSuccessful)
    .switchIfEmpty(Fuel.get("/status/200").monoResponse())
    .map(Response::statusCode)
    .subscribe(::println)
```


# Forge

The forge extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-forge` with `Maven` and `Gradle`. The forge package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Forge: 1.0.0-alpha2

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-forge:<latest-version>'
```

## Usage

See `FuelForge.kt`


# Gson

The gson extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-gson` with `Maven` and `Gradle`. The gson package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Gson: 2.8.5

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-gson:<latest-version>'
```

## Usage

See `FuelGson.kt`

### Gson Deserialization

* Fuel also provides a built in support for Gson Deserialization. This is possible by including the [Gson](https://github.com/kittinunf/Fuel/tree/master/fuel-gson) module in your dependency block.

```kotlin
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent").responseObject<HttpBinUserAgentModel> { _, _, result -> 
  // handle result similarly as it is shown by the core module
}
```


# Jackson

The jackson extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-jackson` with `Maven` and `Gradle`. The jackson package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Jackson: 2.9.8

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-jackson:<latest-version>'
```

## Usage

The Fuel-Jackson module provides a built in support for Jackson serialization and deserialization.

### Serialization

The serialization is done by adding the `objectBody` extension function into Fuel `Request` interface.

By default, the `objectBody` call will use the `Charsets.UTF-8` charset and the `defaultMapper` property defined in `FuelJackson.kt`.

```kotlin
data class FakeObject(val foo: String = "foo")

Fuel.post("/fooBar")
    .objectBody(FakeObject())
```

Alternatively, you can provide a custom `charset` as a parameter to it.

```kotlin
data class FakeObject(val foo: String = "foo")

Fuel.post("/fooBar")
    .objectBody(FakeObject(), Charsets.UTF_16)
```

You can also provide your own `ObjectMapper` as a parameter.

```kotlin
data class FakeObject(val foo: String = "foo")

val mapper = ObjectMapper().registerKotlinModule()
                           .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

mapper.propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE

Fuel.post("/fooBar")
    .objectBody(FakeObject(), mapper = mapper)
```

### Deserialization

The deserialization is done by adding the `responseObject` extension function into Fuel `Request` interface.

By default, the `responseObject` call will use the `defaultMapper` property defined in `FuelJackson.kt`.

```kotlin
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel>()
```

Alternatively, you can provide your own `ObjectMapper` as a parameter to it.

```kotlin
data class HttpBinUserAgentModel(var userAgent: String = "")

val mapper = ObjectMapper().registerKotlinModule()
                           .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

mapper.propertyNamingStrategy = PropertyNamingStrategy.SNAKE_CASE

Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel>(mapper)
```

Also, the `responseObject` overloads allows you to pass `Response Handlers` as lambda functions

```kotlin
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent").responseObject<HttpBinUserAgentModel> { request, response, result ->
    //handle here
}
```

or `ResponseHandler<T>` instances.

```kotlin
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .responseObject(object : ResponseHandler<HttpBinUserAgentModel> {
           override fun success(request: Request, response: Response, value: HttpBinUserAgentModel) {
              //handle success
           }

           override fun failure(request: Request, response: Response, error: FuelError) {
              //handle failure
           }
     })
```

Both overloads allows you to provide custom `ObjectMapper` if needed.


# Json

The Json extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-json` with `Maven` and `Gradle`. The json package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Json: 20170516

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-json:<latest-version>'
```

## Usage

```kotlin
fun responseJson(handler: (Request, Response, Result<FuelJson, FuelError>) -> Unit)

val jsonObject = json.obj() //JSONObject
val jsonArray = json.array() //JSONArray
```

See `FuelJson.kt`


# Kotlinx-Serialization

The kotlinx-serialization extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-kotlinx-serialization` with `Maven` and `Gradle`. The kotlinx-serialization package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* [KotlinX Serialization](https://github.com/Kotlin/kotlinx.serialization#gradle): 1.0.1

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-kotlinx-serialization:<latest-version>'
```

## Usage

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel> { _, _, result -> }
```

This is by default strict and will reject unknown keys, for that you can pass a custom Json instance `Json(strictMode = false)` or use a built-in alternate like `Json.nonstrict`

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel>(json = Json.nonstrict) { _, _, result -> }
```

`kotlinx.serialization` can not always guess the correct serialzer to use, when generics are involved for example

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/list/user-agent")
    .responseObject<HttpBinUserAgentModel>(loader = HttpBinUserAgentModel.serializer().list) { _, _, result -> }
```

It can be used with coroutines by using `kotlinxDeserializerOf()` it takes the same `json` and `loader` as parameters

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .awaitResponseObject<HttpBinUserAgentModel>(kotlinxDeserializerOf()) { _, _, result -> }
```


# Moshi

The moshi extension package for [`Fuel`](broken://pages/-LS8kbBJjT2_gwYkij4g).

## Installation

You can [download](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) and install `fuel-moshi` with `Maven` and `Gradle`. The moshi package has the following dependencies:

* [`Fuel`](/documentation/core/fuel)
* Moshi: 1.8.0

```groovy
implementation 'com.github.kittinunf.fuel:fuel:<latest-version>'
implementation 'com.github.kittinunf.fuel:fuel-moshi:<latest-version>'
```

## Usage

See `FuelMoshi.kt`


# v1.x.y

[![Kotlin](https://img.shields.io/badge/Kotlin-1.3.0-blue.svg)](https://kotlinlang.org) [![bintray](https://api.bintray.com/packages/kittinunf/maven/Fuel-Android/images/download.svg)](https://bintray.com/kittinunf/maven/Fuel-Android/_latestVersion) [![Build Status](https://travis-ci.org/kittinunf/Fuel.svg?branch=master)](https://travis-ci.org/kittinunf/Fuel) [![Codecov](https://codecov.io/github/kittinunf/Fuel/coverage.svg?branch=master)](https://codecov.io/gh/kittinunf/Fuel)

The easiest HTTP networking library for Kotlin/Android.

## Features

* [x] Support basic HTTP GET/POST/PUT/DELETE/HEAD/PATCH in a fluent style interface
* [x] Support both asynchronous and blocking requests
* [x] Download file
* [x] Upload file (multipart/form-data)
* [x] Cancel in-flight request
* [x] Request timeout
* [x] Configuration manager by using `FuelManager`
* [x] Debug log / cUrl log
* [x] Support response deserialization into plain old object (both Kotlin & Java)
* [x] Automatically invoke handler on Android Main Thread when using Android Module
* [x] Special test mode for easier testing
* [x] Support for reactive programming via RxJava 2.x and Project Reactor 3.x
* [x] Google Components [LiveData](https://developer.android.com/topic/libraries/architecture/livedata.html) support
* [x] Built-in object serialization module (kotlinx-serialization, Gson, Jackson, Moshi, Forge) :sparkles:
* [x] Support Kotlin's [Coroutines](https://github.com/Kotlin/kotlinx.coroutines) module
* [x] API Routing

## Installation

### There are 2 versions of Fuel build against different Kotlin Versions

#### [![Download](https://api.bintray.com/packages/kittinunf/maven/Fuel-Android/images/download.svg?version=1.15.1)](https://bintray.com/kittinunf/maven/Fuel-Android/1.15.1/link)

* Kotlin - 1.2.71
* Coroutine - 0.23.3

#### [![Download](https://api.bintray.com/packages/kittinunf/maven/Fuel-Android/images/download.svg?version=1.16.0)](https://bintray.com/kittinunf/maven/Fuel-Android/1.16.0/link)

* Kotlin - 1.3.0-rc-146
* Coroutine - 0.30.1-eap13

### Dependency - fuel

* [Result](https://github.com/kittinunf/Result) - The modelling for success/failure of operations in Kotlin

### Dependency - fuel-android

* [Android SDK](https://developer.android.com/studio/index.html) - Android SDK
* Min SDK: 19&#x20;

### Dependency - fuel-livedata

* [Live Data](https://developer.android.com/topic/libraries/architecture/livedata.html) - Android Architecture Components - LiveData

### Dependency - fuel-rxjava

* [RxJava](https://github.com/ReactiveX/RxJava) - RxJava – Reactive Extensions for the JVM

### Dependency - fuel-coroutines

* [Coroutines](https://github.com/Kotlin/kotlinx.coroutines) - Kotlin Coroutines - Library support for Kotlin coroutines

### Dependency - fuel-kotlinx-serialization

* [Kotlinx Serialization](https://github.com/Kotlin/kotlinx.serialization) - Kotlinx Serialization - Kotlin cross-platform / multi-format serialization

### Dependency - fuel-gson

* [Gson](https://github.com/google/gson) - Gson - A Java serialization/deserialization library to convert Java Objects into JSON and back

### Dependency - fuel-jackson

* [Jackson](https://github.com/FasterXML/jackson-module-kotlin) - Jackson - The JSON library for Java

### Dependency - fuel-moshi

* [Moshi](https://github.com/square/moshi) - Moshi - A modern JSON library for Android and Java

### Dependency - fuel-forge

* [Forge](https://github.com/kittinunf/Forge/) - Forge - Functional style JSON parsing written in Kotlin

### Dependency - fuel-reactor

* [Project Reactor](https://github.com/reactor/reactor-core) - Project Reactor - Implementation of Reactive Streams standard

### Gradle

```groovy
repositories {
    jcenter()
}

dependencies {
    compile 'com.github.kittinunf.fuel:fuel:<latest-version>' //for JVM
    compile 'com.github.kittinunf.fuel:fuel-android:<latest-version>' //for Android
    compile 'com.github.kittinunf.fuel:fuel-livedata:<latest-version>' //for LiveData support
    compile 'com.github.kittinunf.fuel:fuel-rxjava:<latest-version>' //for RxJava support
    compile 'com.github.kittinunf.fuel:fuel-coroutines:<latest-version>' //for Kotlin Coroutines support
    compile 'com.github.kittinunf.fuel:fuel-gson:<latest-version>' //for Gson support
    compile 'com.github.kittinunf.fuel:fuel-jackson:<latest-version>' //for Jackson support
    compile 'com.github.kittinunf.fuel:fuel-moshi:<latest-version>' //for Moshi support
    compile 'com.github.kittinunf.fuel:fuel-forge:<latest-version>' //for Forge support
    compile 'com.github.kittinunf.fuel:fuel-reactor:<latest-version>' //for Reactor support
}
```

### Sample

* There are two samples, one is in Kotlin and another one in Java.

## Quick Glance Usage

#### Async mode

* Kotlin

  \`\`\`kotlin

  //an extension over string (support GET, PUT, POST, DELETE with httpGet(), httpPut(), httpPost(), httpDelete())

  "<https://httpbin.org/get".httpGet().responseString> { request, response, result ->

  //do something with response

  when (result) {

  &#x20; is Result.Failure -> {

  ```
  val ex = result.getException()
  ```

  &#x20; }

  &#x20; is Result.Success -> {

  ```
  val data = result.get()
  ```

  &#x20; }

  }

  }

//if we set baseURL beforehand, simply use relativePath FuelManager.instance.basePath = "<https://httpbin.org>" "/get".httpGet().responseString { request, response, result -> //make a GET to <https://httpbin.org/get> and do something with response val (data, error) = result if (error == null) { //do something when success } else { //error handling } }

//if you prefer this a little longer way, you can always do //get Fuel.get("<https://httpbin.org/get").responseString> { request, response, result -> //do something with response result.fold({ d -> //do something with data }, { err -> //do something with error }) }

````
* Java
```java
//get
Fuel.get("https://httpbin.org/get", params).responseString(new Handler<String>() {
    @Override
    public void failure(Request request, Response response, FuelError error) {
        //do something when it is failure
    }

    @Override
    public void success(Request request, Response response, String data) {
        //do something when it is successful
    }
});
````

#### Blocking mode

You can also wait for the response. It returns the same parameters as the async version, but it blocks the thread. It supports all the features of the async version.

* Kotlin

  ```kotlin
  val (request, response, result) = "https://httpbin.org/get".httpGet().responseString() // result is Result<String, FuelError>
  ```
* Java

  \`\`\`java try { Triple data = Fuel.get("<https://www.google.com").responseString(>); Request request = data.getFirst(); Response response = data.getSecond(); Result text = data.getThird(); } catch (Exception networkError) {

}

````
## Detail Usage

### GET

```kotlin
Fuel.get("https://httpbin.org/get").response { request, response, result ->
    println(request)
    println(response)
    val (bytes, error) = result
    if (bytes != null) {
        println(bytes)
    }
}
````

### Response Handling

### Result

* [Result](https://github.com/kittinunf/Result) is a functional style data structure that represents data that contains result of *Success* or *Failure* but not both. It represents the result of an action that can be success (with result) or error.
* Working with result is easy. You could [*fold*](https://github.com/kittinunf/Fuel/blob/master/fuel/src/test/kotlin/com/github/kittinunf/fuel/RequestTest.kt#L324), [*destructure*](https://github.com/kittinunf/Fuel/blob/master/fuel/src/test/kotlin/com/github/kittinunf/fuel/RequestTest.kt#L266) as because it is just a [data class](https://kotlinlang.org/docs/reference/data-classes.html) or do a simple `when` checking whether it is *Success* or *Failure*.

### Response

```kotlin
fun response(handler: (Request, Response, Result<ByteArray, FuelError>) -> Unit)
```

### Response in String

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

### Response in Json

*requires the* [*android extension*](/documentation/legacy/readme-legacy#dependency---fuel-android)

```kotlin
fun responseJson(handler: (Request, Response, Result<Json, FuelError>) -> Unit)

val jsonObject = json.obj() //JSONObject
val jsonArray = json.array() //JSONArray
```

### Response in T (object)

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

### POST

```kotlin
Fuel.post("https://httpbin.org/post").response { request, response, result ->
}

// JSON body from string (automatically sets application/json as Content-Type)
Fuel.post("https://httpbin.org/post")
    .jsonBody("{ \"foo\" : \"bar\" }")
    .response { request, response, result -> }

// Body from a generic string
Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body("my body is plain")
    .response { request, response, result -> }

// Body from a file
Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body(File("lipsum.txt"))
    .response { request, response, result -> }

// Body from a generic stream
val stream = ByteArrayInputStream("source-string-from-string".toByteArray())
Fuel.post("https://httpbin.org/post")
    .header(Headers.CONTENT_TYPE, "text/plain")
    .body(stream)
    .response { request, response, result -> }
```

### PUT

```kotlin
Fuel.put("https://httpbin.org/put")
    .response { request, response, result -> }

// Supports all the body methods, like POST requests
```

### DELETE

```kotlin
Fuel.delete("https://httpbin.org/delete")
    .response { request, response, result -> }

// Supports all the body methods, like POST requests
```

### HEAD

```kotlin
Fuel.head("https://httpbin.org/get")
    .response { request, response, result -> /* request body is empty */ }
```

### PATCH

* The default `client` is [`HttpClient`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/com/github/kittinunf/fuel/toolbox/HttpClient.kt) which is a thin wrapper over [`java.net.HttpUrlConnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html). [`java.net.HttpUrlConnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html) does not support a \[`PATCH`]\(<https://download.java.net/jdk7/archive/b123/docs/api/java/net/HttpURLConnection.html#setRequestMethod(java.lang.String>)) method. [`HttpClient`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/com/github/kittinunf/fuel/toolbox/HttpClient.kt) converts `PATCH` requests to a `POST` request and adds a `X-HTTP-Method-Override: PATCH` header. While this is a semi-standard industry practice not all APIs are configured to accept this header by default.

```kotlin
Fuel.patch("https://httpbin.org/patch").response { request, response, result -> }

// Supports all the body methods, like POST requests
```

### CONNECT

Connect is not supported by the Java JVM via the regular HTTP clients, and is therefore not supported.

### OPTIONS

There are no convenience methods for making an OPTIONS request, but you can still make one directly:

```kotlin
Fuel.request(Method.OPTIONS, "https://httpbin.org/anything")
    .response { request, response, result -> }
```

### TRACE

There are no convenience methods for making an TRACE request, but you can still make one directly:

```kotlin
Fuel.request(Method.TRACE, "https://httpbin.org/anything")
    .response { request, response, result -> }
```

### Debug Logging

* Use `toString()` method to inspect requests

```kotlin
val request = Fuel.get("https://httpbin.org/get", parameters = listOf("key" to "value"))
println(request)

// --> GET (https://httpbin.org/get?key=value)
//    Body : (empty)
//    Headers : (2)
//    Accept-Encoding : compress;q=0.5, gzip;q=1.0
//    Device : Android
```

* Use `toString()` method to inspect responses

```kotlin
val (_, response, _) = Fuel.get("https://httpbin.org/get", parameters = listOf("key" to "value")).response()
println(response)
// <-- 200 (https://httpbin.org/get?key=value)
//    Body : (empty)
```

* Also support cUrl string to Log request, make it very easy to cUrl on command line

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

```bash
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"
```

### Parameter Support

* URL encoded style for GET & DELETE request

```kotlin
Fuel.get("https://httpbin.org/get", listOf("foo" to "foo", "bar" to "bar"))
    .response { request, response, result -> }
// resolve to https://httpbin.org/get?foo=foo&bar=bar

Fuel.delete("https://httpbin.org/delete", listOf("foo" to "foo", "bar" to "bar"))
    .response { request, response, result -> }
// resolve to https://httpbin.org/delete?foo=foo&bar=bar
```

* Array support for GET requests

```kotlin
Fuel.get("https://httpbin.org/get", listOf("foo" to "foo", "dwarf" to  arrayOf("grumpy","happy","sleepy","dopey")))
    .response { request, response, result -> }
// resolve to  https://httpbin.org/get?foo=foo&dwarf[]=grumpy&dwarf[]=happy&dwarf[]=sleepy&dwarf[]=dopey
```

* Support x-www-form-urlencoded for PUT & POST

```kotlin
Fuel.post("https://httpbin.org/post", listOf("foo" to "foo", "bar" to "bar"))
    .response { request, response, result -> }
// Body : "foo=foo&bar=bar"

Fuel.put("https://httpbin.org/put", listOf("foo" to "foo", "bar" to "bar"))
    .response { request, response, result -> }
// Body : "foo=foo&bar=bar"
```

### Set request's timeout and read timeout

Default timeout for a request is 15000 milliseconds. Default read timeout for a request is 15000 milliseconds.

* Kotlin

  \`\`\`kotlin

  val timeout = 5000 // 5000 milliseconds = 5 seconds.

  val timeoutRead = 60000 // 60000 milliseconds = 1 minute.

Fuel.get("<https://httpbin.org/get>") .timeout(timeout) .timeoutRead(timeoutRead) .responseString { request, response, result -> }

````
* Java
```java
int timeout = 5000 // 5000 milliseconds = 5 seconds.
int timeoutRead = 60000 // 60000 milliseconds = 1 minute.
Fuel.get("https://httpbin.org/get", params).timeout(timeout).timeoutRead(timeoutRead).responseString(new Handler<String>() {
    @Override
    public void failure(Request request, Response response, FuelError error) {
        //do something when it is failure
    }

    @Override
    public void success(Request request, Response response, String data) {
        //do something when it is successful
    }
});
````

### Download with or without progress handler

```kotlin
Fuel.download("https://httpbin.org/bytes/32768")
    .destination { response, url -> File.createTempFile("temp", ".tmp") }
    .response { req, res, result -> }

Fuel.download("https://httpbin.org/bytes/32768")
    .destination { response, url -> File.createTempFile("temp", ".tmp") }
    .progress { readBytes, totalBytes ->
        val progress = readBytes.toFloat() / totalBytes.toFloat() * 100
        println("Bytes downloaded $readBytes / $totalBytes ($progress %)")
    }
    .response { req, res, result -> }
```

### Upload with or without progress handler

```kotlin
Fuel.upload("/post")
    .source { request, url -> File.createTempFile("temp", ".tmp") }
    .responseString { request, response, result -> }

// By default upload use Method.POST, unless it is specified as something else
Fuel.upload("/put", Method.PUT)
    .source { request, url -> File.createTempFile("temp", ".tmp") }
    .responseString { request, response, result -> }

// Upload with multiple files
Fuel.upload("/post")
    .sources { request, url ->
        listOf(
            File.createTempFile("temp1", ".tmp"),
            File.createTempFile("temp2", ".tmp")
        )
    }
    .name { "temp" }
    .responseString { request, response, result -> }
```

### Specify custom field names for files

```kotlin
Fuel.upload("/post")
    .dataParts { request, url -> 
        listOf( 
            //DataPart takes a file, and you can specify the name and/or type
            DataPart(File.createTempFile("temp1", ".tmp"), "image/jpeg"), 
            DataPart(File.createTempFile("temp2", ".tmp"), "file2"), 
            DataPart(File.createTempFile("temp3", ".tmp"), "third-file", "image/jpeg") 
        ) 
    }
    .responseString { request, response, result -> /* ... */ }
```

### Upload a multipart form without a file

```kotlin
val formData = listOf("Email" to "mail@example.com", "Name" to "Joe Smith" )
Fuel.upload("/post", param = formData)
    // Upload normally requires a file, but we can give it an empty list of `DataPart`
    .dataParts { request, url -> listOf<DataPart>() } 
    .responseString { request, response, result -> /* ... */ }
```

### Upload from an `InputStream`

```kotlin
Fuel.upload("/post")
    .blob { request, url -> Blob("filename.png", someObject.length) { someObject.getInputStream() } }
```

### Authentication

* Support *Basic Authentication* right off the box

  ```kotlin
    val username = "username"
    val password = "abcd1234"

    Fuel.get("https://httpbin.org/basic-auth/$user/$password")
        .basicAuthentication(username, password)
        .response { request, response, result -> }
  ```
* Support *Bearer Authentication*

  ```kotlin
    val token = "mytoken"

    Fuel.get("https://httpbin.org/bearer")
        .bearerAuthentication(token)
        .response { request, response, result -> }
  ```
* Support *Any authentication* by header

  ```kotlin
    Fuel.get("https://httpbin.org/anything")
        .header(Headers.AUTHORIZATION, "Custom secret")
        .response { request, response, result -> }
  ```

### Validation

* By default, the valid range for HTTP status code will be (200..299).

### Cancel

* If one wants to cancel on-going request, one could call `cancel` on the request object

  ```kotlin
    val request = Fuel.get("https://httpbin.org/get")
      .response { request, response, result ->
        // if request is cancelled successfully, response callback will not be called. 
        // Interrupt callback (if provided) will be called instead
      }

    //later
    request.cancel() //this will cancel on-going request
  ```
* Also, interrupt request can be further processed with interrupt callback

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

    request.cancel()
  ```

## Advanced Configuration

### Response Deserialization

* Fuel provides built-in support for response deserialization. Here is how one might want to use Fuel together with [Gson](https://github.com/google/gson)

  \`\`\`kotlin //User Model data class User(val firstName: String = "", val lastName: String = "") {

  //User Deserializer class Deserializer : ResponseDeserializable { override fun deserialize(content: String) = Gson().fromJson(content, User::class.java) }

}

//Use httpGet extension "<https://www.example.com/user/1".httpGet().responseObject(User.Deserializer(>)) { req, res, result -> //result is of type Result val (user, err) = result

```
println(user.firstName)
println(user.lastName)
```

}

````
### Gson Deserialization

* Fuel also provides a built in support for Gson Deserialization. This is possible by including the [Gson](https://github.com/kittinunf/Fuel/tree/master/fuel-gson) module in your dependency block.

```kotlin
data class HttpBinUserAgentModel(var userAgent: String = "")
Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel> { _, _, result -> }
````

### Deserialization using kotlinx.serialzationn

*requires the* [*kotlinx-serialization extension*](/documentation/legacy/readme-legacy#dependency---fuel-kotlinx-serialization) *requires* [*kotlinx.serialization*](https://github.com/Kotlin/kotlinx.serialization#gradlejvm)

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel> { _, _, result -> }
```

This is by default strict and will reject unknown keys, for that you can pass a custom JSOn instance

`JSON(nonstrict = true)`

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .responseObject<HttpBinUserAgentModel>(json = JSON(nonstrict = true)) { _, _, result -> }
```

`kotlinx.serialization` can not always guess the correct serialzer to use, when generics are involved for example

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/list/user-agent")
    .responseObject<HttpBinUserAgentModel>(loader = HttpBinUserAgentModel.serilaizer().list) { _, _, result -> }
```

It can be used with coroutines by using `kotlinxDeserilaizerOf()` it takes the same `json` and `loader` as parameters

```kotlin
@Serializable
data class HttpBinUserAgentModel(var userAgent: String = "")

Fuel.get("/user-agent")
    .awaitResponseObject<HttpBinUserAgentModel>(kotlinxDeserializerOf()) { _, _, result -> }
```

* There are 4 methods to support response deserialization depending on your needs (also depending on JSON parsing library of your choice), and you are required to implement only one of them.

  ```kotlin
    fun deserialize(bytes: ByteArray): T?

    fun deserialize(inputStream: InputStream): T?

    fun deserialize(reader: Reader): T?

    fun deserialize(content: String): T?
  ```
* Another example may be parsing a website that is not UTF-8. By default, Fuel serializes text as UTF-8, we need to define our deserializer as such

  ```kotlin
    object Windows1255StringDeserializer : ResponseDeserializable<String> {
        override fun deserialize(bytes: ByteArray): String {
            return String(bytes, "windows-1255")
        }
    }
  ```

### Configuration

* Use singleton `FuelManager.instance` to manage global configurations.
* `basePath` is used to manage common root path. Great usage is for your static API endpoint.

  ```kotlin
    FuelManager.instance.basePath = "https://httpbin.org"

    // Later
    Fuel.get("/get").response { request, response, result ->
        //make request to https://httpbin.org/get because Fuel.{get|post|put|delete} use FuelManager.instance to make HTTP request
    }
  ```
* `baseHeaders` is to manage common HTTP header pairs in format of `Map<String, String>`.
  * The base headers are only applied if the request does not have those headers set.

    ```kotlin
    FuelManager.instance.baseHeaders = mapOf("Device" to "Android")
    ```
* `Headers` can be added to a request via various methods including
  * `fun header(name: String, value: Any): Request`: `request.header("foo", "a")`
  * `fun header(pairs: Map<String, Any>): Request`: `request.header(mapOf("foo" to "a"))`
  * `fun header(vararg pairs: Pair<String, Any>): Request`: `request.header("foo" to "a")`
  * `operator fun set(header: String, value: Collection<Any>): Request`: `request["foo"] = listOf("a", "b")`
  * `operator fun set(header: String, value: Any): Request`: `request["foo"] = "a"`
* By default, all subsequent calls overwrite earlier calls, but you may use the `appendHeader` variant to append values to existing values.
  * In earlier versions a `mapOf` overwrote, and `varargs pair` did not, but this was confusing.
* Some of the HTTP headers are defined under `Headers.Companion` and can be used instead of literal strings.

  ```kotlin
    Fuel.post("/my-post-path")
        .header(Headers.ACCEPT, "text/html, */*; q=0.1")
        .header(Headers.CONTENT_TYPE, "image/png")
        .header(Headers.COOKIE to "basic=very")
        .appendHeader(Headers.COOKIE to "value_1=foo", Headers.COOKIE to "value_2=bar", Headers.ACCEPT to "application/json")
        .appendHeader("MyFoo" to "bar", "MyFoo" to "baz")
        .response { /*...*/ }

     // => request with:
     //    Headers:
     //      Accept: "text/html, */*; q=0.1, application/json"
     //      Content-Type: "image/png"
     //      Cookie: "basic=very; value_1=foo; value_2=bar"
     //      MyFoo: "bar, baz"
  ```
* `baseParams` is used to manage common `key=value` query param, which will be automatically included in all of your subsequent requests in format of `Parameters` (`Any` is converted to `String` by `toString()` method)

  ```kotlin
    FuelManager.instance.baseParams = listOf("api_key" to "1234567890")

    // Later
    Fuel.get("/get").response { request, response, result ->
        //make request to https://httpbin.org/get?api_key=1234567890
    }
  ```
* `client` is a raw HTTP client driver. Generally, it is responsible to make [`Request`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/fuel/core/Request.kt) into [`Response`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/fuel/core/Response.kt). Default is [`HttpClient`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/fuel/toolbox/HttpClient.kt) which is a thin wrapper over [`java.net.HttpUrlConnection`](https://developer.android.com/reference/java/net/HttpURLConnection.html). You could use any httpClient of your choice by conforming to [`client`](https://github.com/kittinunf/Fuel/blob/master/fuel/src/main/kotlin/com/github/kittinunf/fuel/core/Client.kt) protocol, and set back to `FuelManager.instance` to kick off the effect.
* `keyStore` is configurable by user. By default it is `null`.
* `socketFactory` can be supplied by user. If `keyStore` is not null, `socketFactory` will be derived from it.
* `hostnameVerifier` is configurable by user. By default, it uses `HttpsURLConnection.getDefaultHostnameVerifier()`.
* `requestInterceptors` `responseInterceptors` is a side-effect to add to `Request` and/or `Response` objects.
  * For example, one might wanna print cUrlString style for every request that hits server in DEBUG mode.

    ```kotlin
      val manager = FuelManager()
      if (BUILD_DEBUG) {
          manager.addRequestInterceptor(cUrlLoggingRequestInterceptor())
      }
      val (request, response, result) = manager.request(Method.GET, "https://httpbin.org/get").response() //it will print curl -i -H "Accept-Encoding:compress;q=0.5, gzip;q=1.0" "https://httpbin.org/get"
    ```
  * Another example is that you might wanna add data into your Database, you can achieve that with providing `responseInterceptors` such as

    ```kotlin
      inline fun <reified T> DbResponseInterceptor() =
          { next: (Request, Response) -> Response ->
              { req: Request, res: Response ->
                  val db = DB.getInstance()
                  val instance = Parser.getInstance().parse(res.data, T::class)
                  db.transaction {
                      it.copyToDB(instance)
                  }
                  next(req, res)
              }
          }

      manager.addResponseInterceptor(DBResponseInterceptor<Dog>)
      manager.request(Method.GET, "https://www.example.com/api/dog/1").response() // Db interceptor will be called to intercept data and save into Database of your choice
    ```

### Test mode

Testing asynchronized calls can be somehow hard without special care. That's why Fuel has a special test mode with make all the requests blocking, for tests.

```kotlin
Fuel.testMode {
    timeout = 15000 // Optional feature, set all requests' timeout to this value.
}
```

In order to disable test mode, just call `Fuel.regularMode()`

### RxJava Support

* Fuel supports [RxJava](https://github.com/ReactiveX/RxJava) right off the box.

  ```kotlin
    "https://www.example.com/photos/1".httpGet()
      .toRxObject(Photo.Deserializer())
      .subscribe { /* do something */ }
  ```
* There are 6 extensions over `Request` that provide RxJava 2.x `Single<Result<T, FuelError>>` as return type.

  ```kotlin
    fun Request.toRxResponse(): Single<Pair<Response, Result<ByteArray, FuelError>>>
    fun Request.toRxResponseString(charset: Charset): Single<Pair<Response, Result<String, FuelError>>>
    fun <T : Any> Request.toRxResponseObject(deserializable: Deserializable<T>): Single<Pair<Response, Result<T, FuelError>>>

    fun Request.toRxData(): Single<Result<ByteArray, FuelError>>
    fun Request.toRxString(charset: Charset): Single<Result<String, FuelError>>
    fun <T : Any> Request.toRxObject(deserializable: Deserializable<T>): Single<Result<T, FuelError>>
  ```

### LiveData Support

* Fuel supports [LiveData](https://developer.android.com/topic/libraries/architecture/livedata.html)

  ```kotlin
  Fuel.get("www.example.com/get")
    .liveDataResponse()
    .observe(this) { /* do something */ }
  ```

### Routing Support

In order to organize better your network stack FuelRouting interface allows you to easily setup a Router design pattern.

```kotlin
sealed class WeatherApi: FuelRouting {

    override val basePath = "https://www.metaweather.com"

    class weatherFor(val location: String): WeatherApi() {}

    override val method: Method
        get() {
            when(this) {
                is weatherFor -> return Method.GET
            }
        }

    override val path: String
        get() {
            return when(this) {
                is weatherFor -> "/api/location/search/"
            }
        }

    override val params: Parameters?
        get() {
            return when(this) {
                is weatherFor -> listOf("query" to this.location)
            }
        }

    override val headers: Map<String, String>?
        get() {
            return null
        }

}


// Usage
Fuel.request(WeatherApi.weatherFor("london"))
    .responseJson { request, response, result ->
        result.fold(success = { json ->
            Log.d("qdp success", json.array().toString())
        }, failure = { error ->
            Log.e("qdp error", error.toString())
        })
    }
```

### Coroutines Support

Coroutines module provides extension functions to wrap a response inside a coroutine and handle its result. The coroutines-based API provides equivalent methods to the standard API (e.g: `responseString()` in coroutines is `awaitStringResponse()`).

```kotlin
runBlocking {
    val (request, response, result) = Fuel.get("https://httpbin.org/ip").awaitStringResponse()

    result.fold(
        { data -> println(data) /* "{"origin":"127.0.0.1"}" */ }, 
        { error -> println("An error of type ${error.exception} happened: ${error.message}") }
    )
}
```

There are functions to handle `Result` object directly too.

```kotlin
runBlocking {
    Fuel.get("https://httpbin.org/ip")
        .awaitStringResult()
        .fold(
            { data -> println(data) /* "{"origin":"127.0.0.1"}" */ }, 
            { error -> println("An error of type ${error.exception} happened: ${error.message}") }
        )
}
```

It also provides useful methods to retrieve the `ByteArray`,`String` or `Object` directly. The difference with these implementations is that they throw exception instead of returning it wrapped a `FuelError` instance.

```kotlin
runBlocking {
    try {
        println(Fuel.get("https://httpbin.org/ip").awaitString()) // "{"origin":"127.0.0.1"}"
    } catch(exception: Exception) {
        println("A network request exception was thrown: ${exception.message}")
    }
}
```

Handling objects other than `String` (`awaitStringResponse()`) or `ByteArray` (`awaitByteArrayResponse()`) can be done using `awaitObject`, `awaitObjectResult` or `awaitObjectResponse`.

```kotlin
data class Ip(val origin: String)

object IpDeserializer : ResponseDeserializable<Ip> {
    override fun deserialize(content: String) =
        jacksonObjectMapper().readValue<Ip>(content)
}
```

```kotlin
runBlocking {
    Fuel.get("https://httpbin.org/ip")
        .awaitObjectResult(IpDeserializer)
        .fold(
            { data -> println(data.origin) /* 127.0.0.1 */ }, 
            { error -> println("An error of type ${error.exception} happened: ${error.message}") }
        )
}
```

```kotlin
runBlocking {
    try {
        val data = Fuel.get("https://httpbin.org/ip").awaitObject(IpDeserializer)
        println(data.origin) // 127.0.0.1
    } catch (exception: Exception) {
        when (exception){
            is HttpException -> println("A network request exception was thrown: ${exception.message}")
            is JsonMappingException -> println("A serialization/deserialization exception was thrown: ${exception.message}")
            else -> println("An exception [${exception.javaClass.simpleName}\"] was thrown")
        }
    }
}
```

### Project Reactor

The Reactor module API provides functions starting with the prefix `mono` to handle instances of `Response`, `Result<T, FuelError>` and values directly (`String`, `ByteArray`, `Any`). All functions expose exceptions as `FuelError` instance.

**Data handling example**

```kotlin
Fuel.get("https://icanhazdadjoke.com")
    .header(Headers.ACCEPT to "text/plain")
    .monoString()
    .subscribe(::println)
```

**Error handling example**

```kotlin
data class Guest(val name: String)

object GuestMapper : ResponseDeserializable<Guest> {
    override fun deserialize(content: String) =
        jacksonObjectMapper().readValue<Guest>(content)
}

Fuel.get("/guestName").monoResultObject(GuestMapper)
    .map(Result<Guest, FuelError>::get)
    .map { (name) -> "Welcome to the party, $name!" }
    .onErrorReturn("I'm sorry, your name is not on the list.")
    .subscribe(::println)
```

**Response handling example**

```kotlin
FuelManager.instance.basePath = "https://httpbin.org"

Fuel.get("/status/404").monoResponse()
    .filter(Response::isSuccessful)
    .switchIfEmpty(Fuel.get("/status/200").monoResponse())
    .map(Response::statusCode)
    .subscribe(::println)
```

## Other libraries

If you like Fuel, you might also like other libraries of mine;

* [Result](https://github.com/kittinunf/Result) - The modelling for success/failure of operations in Kotlin
* [Fuse](https://github.com/kittinunf/Fuse) - A simple generic LRU memory/disk cache for Android written in Kotlin
* [Forge](https://github.com/kittinunf/Forge) - Functional style JSON parsing written in Kotlin
* [ReactiveAndroid](https://github.com/kittinunf/ReactiveAndroid) - Reactive events and properties with RxJava for Android SDK

## Credits

Fuel is brought to you by [contributors](https://github.com/kittinunf/Fuel/graphs/contributors).

## Licenses

Fuel is released under the [MIT](https://opensource.org/licenses/MIT) license.


