106

I want to do a login validation using POST method and to get some information using GET method.

I've URL, server Username and Password already of my previous project.

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Rajkumar K
  • 1,369
  • 3
  • 9
  • 13
  • 5
    Have you tried [using **Retrofit**](https://antonioleiva.com/retrofit-android-kotlin/)? You can find Retrofit [**here**](http://square.github.io/retrofit/) – EpicPandaForce Sep 12 '17 at 14:51
  • If/when Android starts to support the new [HTTP Client API](https://openjdk.java.net/groups/net/httpclient/intro.html) of Java 11, that would be a great option too. (Currently, [this part of Java 11 it is not supported on Android](https://jakewharton.com/androids-java-9-10-11-and-12-support/#:~:text=A%20major%20API%20addition%20to%20Java%2011%20is%20the%20new%20HTTP%20client) as far as I know). See [this post](https://stackoverflow.com/q/65363995/8583692). – Mahozad Dec 31 '21 at 17:47

11 Answers11

85

For Android, Volley is a good place to get started. For all platforms, you might also want to check out ktor client or http4k which are both good libraries.

However, you can also use standard Java libraries like java.net.HttpURLConnection which is part of the Java SDK:

fun sendGet() {
    val url = URL("http://www.google.com/")

    with(url.openConnection() as HttpURLConnection) {
        requestMethod = "GET"  // optional default is GET

        println("\nSent 'GET' request to URL : $url; Response Code : $responseCode")

        inputStream.bufferedReader().use {
            it.lines().forEach { line ->
                println(line)
            }
        }
    }
}

Or simpler:

URL("https://google.com").readText()
s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
33

Send HTTP POST/GET request with parameters using HttpURLConnection :

POST with Parameters:

fun sendPostRequest(userName:String, password:String) {

    var reqParam = URLEncoder.encode("username", "UTF-8") + "=" + URLEncoder.encode(userName, "UTF-8")
    reqParam += "&" + URLEncoder.encode("password", "UTF-8") + "=" + URLEncoder.encode(password, "UTF-8")
    val mURL = URL("<Your API Link>")

    with(mURL.openConnection() as HttpURLConnection) {
        // optional default is GET
        requestMethod = "POST"

        val wr = OutputStreamWriter(getOutputStream());
        wr.write(reqParam);
        wr.flush();

        println("URL : $url")
        println("Response Code : $responseCode")

        BufferedReader(InputStreamReader(inputStream)).use {
            val response = StringBuffer()

            var inputLine = it.readLine()
            while (inputLine != null) {
                response.append(inputLine)
                inputLine = it.readLine()
            }
            println("Response : $response")
        }
    }
}

GET with Parameters:

fun sendGetRequest(userName:String, password:String) {

        var reqParam = URLEncoder.encode("username", "UTF-8") + "=" + URLEncoder.encode(userName, "UTF-8")
        reqParam += "&" + URLEncoder.encode("password", "UTF-8") + "=" + URLEncoder.encode(password, "UTF-8")

        val mURL = URL("<Yout API Link>?"+reqParam)

        with(mURL.openConnection() as HttpURLConnection) {
            // optional default is GET
            requestMethod = "GET"

            println("URL : $url")
            println("Response Code : $responseCode")

            BufferedReader(InputStreamReader(inputStream)).use {
                val response = StringBuffer()

                var inputLine = it.readLine()
                while (inputLine != null) {
                    response.append(inputLine)
                    inputLine = it.readLine()
                }
                it.close()
                println("Response : $response")
            }
        }
    }
Vlad
  • 7,997
  • 3
  • 56
  • 43
Deven
  • 3,078
  • 1
  • 32
  • 34
20

Using only the standard library with minimal code!

thread {
    val json = try { URL(url).readText() } catch (e: Exception) { return@thread }
    runOnUiThread { displayOrWhatever(json) }
}

This starts a GET request on a new thread, leaving the UI thread to respond to user input. However, we can only modify UI elements from the main/UI thread, so we actually need a runOnUiThread block to show the result to our user. This enqueues our display code to be run on the UI thread soon.

The try/catch is there so your app won't crash if you make a request with your phone's internet off. Add your own error handling (e.g. showing a Toast) as you please.

.readText() is not part of the java.net.URL class but a Kotlin extension method, Kotlin "glues" this method onto URL. This is enough for plain GET requests, but for more control and POST requests you need something like the Fuel library.

xjcl
  • 12,848
  • 6
  • 67
  • 89
  • Why don't You just wrap the function body as described below instead of only making (useful) warnings?
        var worker = object : AsyncTask() {
    
                    override fun doInBackground(params: Array): Void? {
                        runner()
                        return null 
                    }
    
                    override fun onPostExecute(result: Void?) {
                        super.onPostExecute(result)
                         /*do something with result*/
                     }
                }
                worker.execute()
    
    – Marco Ottina May 27 '20 at 19:55
  • 2
    Hey Marco, I'm currently using _AsyncTask_ as well, but it will be **deprecated in Android 11**. And I haven't experimented with other approaches so I don't feel comfortable explaining them yet, I'll edit my answer later. – xjcl May 27 '20 at 22:01
  • 2
    I've edited my answer to use `thread` instead of `AsyncTask` now. – xjcl Apr 11 '21 at 13:21
14

Have a look at Fuel library, a sample GET request

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

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

A sample POST request

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

Their documentation can be found here

gastrodon
  • 75
  • 3
  • 9
11

I think using okhttp is the easiest solution. Here you can see an example for POST method, sending a json, and with auth.

val url = "https://example.com/endpoint"

val client = OkHttpClient()

val JSON = MediaType.get("application/json; charset=utf-8")
val body = RequestBody.create(JSON, "{\"data\":\"$data\"}")
val request = Request.Builder()
        .addHeader("Authorization", "Bearer $token")
        .url(url)
        .post(body)
        .build()

val  response = client . newCall (request).execute()

println(response.request())
println(response.body()!!.string())

Remember to add this dependency to your project https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp

UPDATE: July 7th, 2019 I'm gonna give two examples using latest Kotlin (1.3.41), OkHttp (4.0.0) and Jackson (2.9.9).

UPDATE: January 25th, 2021 Everything is okay with the most updated versions.

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-kotlin -->
        <dependency>
            <groupId>com.fasterxml.jackson.module</groupId>
            <artifactId>jackson-module-kotlin</artifactId>
            <version>2.12.1</version>
        </dependency>

<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.0</version>
        </dependency>

Get Method

fun get() {
    val client = OkHttpClient()
    val url = URL("https://reqres.in/api/users?page=2")

    val request = Request.Builder()
            .url(url)
            .get()
            .build()

    val response = client.newCall(request).execute()

    val responseBody = response.body!!.string()

    //Response
    println("Response Body: " + responseBody)

    //we could use jackson if we got a JSON
    val mapperAll = ObjectMapper()
    val objData = mapperAll.readTree(responseBody)

    objData.get("data").forEachIndexed { index, jsonNode ->
        println("$index $jsonNode")
    }
}

POST Method

fun post() {
    val client = OkHttpClient()
    val url = URL("https://reqres.in/api/users")

    //just a string
    var jsonString = "{\"name\": \"Rolando\", \"job\": \"Fakeador\"}"

    //or using jackson
    val mapperAll = ObjectMapper()
    val jacksonObj = mapperAll.createObjectNode()
    jacksonObj.put("name", "Rolando")
    jacksonObj.put("job", "Fakeador")
    val jacksonString = jacksonObj.toString()

    val mediaType = "application/json; charset=utf-8".toMediaType()
    val body = jacksonString.toRequestBody(mediaType)

    val request = Request.Builder()
            .url(url)
            .post(body)
            .build()

    val response = client.newCall(request).execute()

    val responseBody = response.body!!.string()

    //Response
    println("Response Body: " + responseBody)

    //we could use jackson if we got a JSON
    val objData = mapperAll.readTree(responseBody)

    println("My name is " + objData.get("name").textValue() + ", and I'm a " + objData.get("job").textValue() + ".")
}
fvildoso
  • 415
  • 8
  • 12
  • 1
    Thanks. That worked for me. But RequestBody.created() is deprecated now. What is the solution ? – Abhijith Konnayil Jul 05 '19 at 13:15
  • what are you imports? I can't figure out which "get" it's supposed to be that goes with what i'm assuming is okhttp MediaType... And what are "$data" and "$token"? Also says "Cannot access 'body': it is private in 'Response'" in "val responseBody = response.body!!.string()" – Raksha Apr 08 '20 at 21:53
  • @Raksha import com.fasterxml.jackson.databind.ObjectMapper import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import java.net.URL import okhttp3.RequestBody.Companion.toRequestBody you should try with the updated examples. – fvildoso Apr 08 '20 at 23:57
  • *Unresolved reference: ObjectMapper* Is it custom class? – J A S K I E R Jan 18 '21 at 11:56
  • @Oleksandr you don't need any custom class. In my example, you have to use OkHttp to do request, and Jackson to serialize JSONs. I've added it the dependencies. – fvildoso Jan 25 '21 at 03:28
10

Maybe the simplest GET

For everybody stuck with NetworkOnMainThreadException for the other solutions: use AsyncTask or, even shorter, (yet still experimental) Coroutines:

launch {

    val jsonStr = URL("url").readText()

}

If you need to test with plain http don't forget to add to your manifest: android:usesCleartextTraffic="true"


For the experimental Coroutines you have to add to build.gradle as of 10/10/2018:

kotlin {
    experimental {
        coroutines 'enable'
    }
}
dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.24.0"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.24.0"
    ...
0llie
  • 8,758
  • 2
  • 24
  • 13
  • Hm, Android Studio says "Experimental coroutines support will be dropped in 1.4" – xjcl Jun 20 '20 at 12:52
  • Looks like coroutines have been moved out of experimental! Also the launch syntax is a bit different now. – xjcl Jun 24 '20 at 21:58
  • Sorry, me again. My IDE tells me "inappropriate blocking method call" for `readText` -- is it okay to use `readText` with coroutines rather than threads? – xjcl Aug 27 '20 at 01:04
6

If you are using Kotlin, you might as well keep your code as succinct as possible. The run method turns the receiver into this and returns the value of the block. this as HttpURLConnection creates a smart cast. bufferedReader().readText() avoids a bunch of boilerplate code.

return URL(url).run {
        openConnection().run {
            this as HttpURLConnection
            inputStream.bufferedReader().readText()
        }
}

You can also wrap this into an extension function.

fun URL.getText(): String {
    return openConnection().run {
                this as HttpURLConnection
                inputStream.bufferedReader().readText()
            }
}

And call it like this

return URL(url).getText()

Finally, if you are super lazy, you can extend the String class instead.

fun String.getUrlText(): String {
    return URL(this).run {
            openConnection().run {
                this as HttpURLConnection
                inputStream.bufferedReader().readText()
            }
    }
}

And call it like this

return "http://somewhere.com".getUrlText()
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
4

You can use kohttp library. It is a Kotlin DSL HTTP client. It supports the features of square.okhttp and provides a clear DSL for them. KoHttp async calls are powered by coroutines.

httpGet extension function

val response: Response = "https://google.com/search?q=iphone".httpGet()

you can also use async call with coroutines

val response: Deferred<Response> = "https://google.com/search?q=iphone".asyncHttpGet()

or DSL function for more complex requests

val response: Response = httpGet {
    host = "google.com"
    path = "/search"
    param {
       "q" to "iphone"
       "safe" to "off"
   }
}

You can find more details in docs

To get it with gradle use

implementation 'io.github.rybalkinsd:kohttp:0.12.0'
Sergei Rybalkin
  • 3,337
  • 1
  • 14
  • 27
  • It depends of your needs. GET method is declared as `fun httpGet(client: Call.Factory = defaultHttpClient, init: HttpGetContext.() -> Unit): Response` so it can use call factory with a configuration specific for your project needs and performance issues. – Sergei Rybalkin Nov 20 '19 at 21:22
3

Without adding additional dependencies, this works. You don't need Volley for this. This works using the current version of Kotlin as of Dec 2018: Kotlin 1.3.10

If using Android Studio, you'll need to add this declaration in your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

You should manually declare imports here. The auto-import tool caused me many conflicts.:

import android.os.AsyncTask
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.net.URL
import java.net.URLEncoder
import javax.net.ssl.HttpsURLConnection

You can't perform network requests on a background thread. You must subclass AsyncTask.

To call the method:

NetworkTask().execute(requestURL, queryString)

Declaration:

private class NetworkTask : AsyncTask<String, Int, Long>() {
    override fun doInBackground(vararg parts: String): Long? {
        val requestURL = parts.first()
        val queryString = parts.last()

        // Set up request
        val connection: HttpsURLConnection = URL(requestURL).openConnection() as HttpsURLConnection
        // Default is GET so you must override this for post
        connection.requestMethod = "POST"
        // To send a post body, output must be true
        connection.doOutput = true
        // Create the stream
        val outputStream: OutputStream = connection.outputStream
        // Create a writer container to pass the output over the stream
        val outputWriter = OutputStreamWriter(outputStream)
        // Add the string to the writer container
        outputWriter.write(queryString)
        // Send the data
        outputWriter.flush()

        // Create an input stream to read the response
        val inputStream = BufferedReader(InputStreamReader(connection.inputStream)).use {
            // Container for input stream data
            val response = StringBuffer()
            var inputLine = it.readLine()
            // Add each line to the response container
            while (inputLine != null) {
                response.append(inputLine)
                inputLine = it.readLine()
            }
            it.close()
            // TODO: Add main thread callback to parse response
            println(">>>> Response: $response")
        }
        connection.disconnect()

        return 0
    }

    protected fun onProgressUpdate(vararg progress: Int) {
    }

    override fun onPostExecute(result: Long?) {
    }
}
jungledev
  • 4,195
  • 1
  • 37
  • 52
3

GET and POST using OkHttp

private const val CONNECT_TIMEOUT = 15L
private const val READ_TIMEOUT = 15L
private const val WRITE_TIMEOUT = 15L

private fun performPostOperation(urlString: String, jsonString: String, token: String): String? {
    return try {
        val client = OkHttpClient.Builder()
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
            .build()

        val body = jsonString.toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())

        val request = Request.Builder()
            .url(URL(urlString))
            .header("Authorization", token)
            .post(body)
            .build()

        val response = client.newCall(request).execute()
        response.body?.string()
    }
    catch (e: IOException) {
        e.printStackTrace()
        null
    }
}

private fun performGetOperation(urlString: String, token: String): String? {
    return try {
        val client = OkHttpClient.Builder()
            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
            .build()

        val request = Request.Builder()
            .url(URL(urlString))
            .header("Authorization", token)
            .get()
            .build()

        val response = client.newCall(request).execute()
        response.body?.string()
    }
    catch (e: IOException) {
        e.printStackTrace()
        null
    }
}

Object serialization and deserialization

@Throws(JsonProcessingException::class)
fun objectToJson(obj: Any): String {
    return ObjectMapper().writeValueAsString(obj)
}

@Throws(IOException::class)
fun jsonToAgentObject(json: String?): MyObject? {
    return if (json == null) { null } else {
        ObjectMapper().readValue<MyObject>(json, MyObject::class.java)
    }
}

Dependencies

Put the following lines in your gradle (app) file. Jackson is optional. You can use it for object serialization and deserialization.

implementation 'com.squareup.okhttp3:okhttp:4.3.1'
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
Mateus Nascimento
  • 815
  • 10
  • 11
0

You can use this library Fuel Library as well, which makes it further easier.

val map = mutableMapOf<String, String>()
    map.put("id","629eeb9da9d8f50016e1af96")

val httpAsync = url
        .httpPost()
        .jsonBody(
             Gson().toJson(map) // for json string
         )
        .responseString { request, response, result -> //do something with the response }
Talha Akbar
  • 621
  • 4
  • 17