When I wanted to perform API communication when creating an Android application, I had to implement it without using the OSS library.
Therefore, I created my own communication part using HttpURLConnection
.
However, an error occurs when I want to send a PATCH request.
It seems that HttpURLConnection
cannot make PATCH requests.
Lie ... I guess ...
There is also a way to spoof using the X-HTTP-Method-Override
header, but it seems uncertain due to server-side dependencies.
https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch
How do you do the OSS library? So, refer to Public Code of the HTTP client library Jersey And implemented it. It's a little old library, but I was able to confirm its operation.
Implement the HttpClient
class as follows.
This time, Bearer authentication is assumed.
HttpClient.kt
internal class HttpClient {
companion object {
fun patch(url: String, accessToken: String? = null, body: String? = null): Pair<Int, String?> {
var responseJsonString: String? = null
val urlTmp = URL(url)
val con = urlTmp.openConnection() as HttpURLConnection
try {
setRequestMethodViaJreBugWorkaround( con, "PATCH")
con.instanceFollowRedirects = false
con.doOutput = true
con.connectTimeout = 60000
con.readTimeout = 60000
con.setRequestProperty("Content-Type", "application/json")
con.setRequestProperty("Accept", "application/json")
if(accessToken != null) con.setRequestProperty("Authorization", "Bearer $accessToken")
if(body != null) {
val os: OutputStream = con.outputStream
val ps = PrintStream(os)
ps.print(body)
ps.close()
}
val reader: BufferedReader
reader = if (con.responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader(InputStreamReader(con.inputStream, "UTF-8"))
} else {
BufferedReader(InputStreamReader(con.errorStream, "UTF-8"))
}
responseJsonString = reader.readLine()
con.disconnect()
} catch (e: Exception) {
e.printStackTrace()
Log.e("ApiClientException", e.toString())
}
return con.responseCode to responseJsonString
}
private fun setRequestMethodViaJreBugWorkaround(httpURLConnection: HttpURLConnection, method: String) {
try {
httpURLConnection.requestMethod = method // Check whether we are running on a buggy JRE
} catch (pe: ProtocolException) {
try {
AccessController.doPrivileged(PrivilegedExceptionAction<Any?> {
try {
httpURLConnection.requestMethod = method
// Check whether we are running on a buggy
// JRE
} catch (pe: ProtocolException) {
var connectionClass: Class<*>? = httpURLConnection.javaClass
val delegateField: Field?
try {
delegateField = connectionClass!!.getDeclaredField("delegate")
delegateField.isAccessible = true
val delegateConnection = delegateField[httpURLConnection] as HttpURLConnection
setRequestMethodViaJreBugWorkaround(delegateConnection, method)
} catch (e: NoSuchFieldException) {
// Ignore for now, keep going
} catch (e: IllegalArgumentException) {
throw RuntimeException(e)
} catch (e: IllegalAccessException) {
throw RuntimeException(e)
}
try {
var methodField: Field
while (connectionClass != null) {
try {
methodField = connectionClass.getDeclaredField("method")
} catch (e: NoSuchFieldException) {
connectionClass = connectionClass.superclass
continue
}
methodField.isAccessible = true
methodField[httpURLConnection] = method
break
}
} catch (e: java.lang.Exception) {
throw RuntimeException(e)
}
}
null
})
} catch (e: PrivilegedActionException) {
val cause: Throwable? = e.cause
if (cause is RuntimeException) {
throw cause
} else {
throw RuntimeException(cause)
}
}
}
}
}
}
Import the above HttpClient
and use it as follows.
fun patchRequestSample() {
val (statusCode, responseJsonString) = HttpClient.patch("https://hoge/users/10", accessToken ="xxxx", body = sampleJson.toString())
}
The status code is returned in statusCode
, and the response is returned in responseJsonString
.
Even if I looked it up, I found only how to override the header, so I'll leave it as a reminder.
Recommended Posts