how can I get GeoJson data from a url in Kotlin - kotlin

I am a beginner in kotlin and I would like to have the information contained in a url:
in my case I have a list of url, each url contains information formatted in geojson and I would like to get this information.
Does anyone have an idea of how I can do this?
here is an example of the url that can be found in my list :
https://database-geojsons-test.s3.amazonaws.com/COOPERATIVES/Maps%2520test/Exploitation/Alpha/Alpha.geojson

you can use Retrofit and add a Gson converterFactory. You can read more about it on the android developer web site.
Here is just an exemple:
private val BASE_URL : String = "http [your URL]"
val interceptor: HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
this.level = HttpLoggingInterceptor.Level.BODY
}
val client: OkHttpClient = OkHttpClient.Builder().apply {
this.addInterceptor(interceptor)
}.build()
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create()) //Converters can be added to support other types in body
.build()
I hope that works for you :)

It's quite simple as I use Retrofit I created a method that will retrieve the json content
#GET
suspend fun getGeoJsonData(#Url url: String) : String
and I could retrieve the content by calling this method for each json

Related

Https request POST issue in Kotlin

I'm new to Kotlin and Android developing.
I'm trying to use the HttpsURL to POST a value of '0' or any other value
to the 'data' variable https://www.mytestsite.com/on-test.php where is a 'data'
variable set inside.
My Kotlin code is reaching the '../on-php' url but the POST method is likely not executed
or no data was transferred for some unknown reason.
I also made another 'post.php' from where I'm posting to the same on-test.php like my Android app,
and that way it is working.
I have no any idea what I'm doing wrong.
Any help I would appreciate.
Here is my code I'm trying to make working:
btn_test.setOnClickListener {
object : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void?): Void? {
val url = "https://www.mytestsite.com/on-test.php"
val data = JSONObject()
data.put("data", "0")
val connection = URL(url).openConnection() as HttpsURLConnection
connection.requestMethod = "POST"
connection.doOutput = true
connection.setRequestProperty("Content-Type", "application/json")
connection.connect()
val wr = DataOutputStream(connection.outputStream)
wr.writeBytes(data.toString())
wr.flush()
wr.close()
error_data = connection.responseMessage
return null
}
}.execute()
text_status.setText(error_data)
}

how to properly use OKHttp FormBody.Builder() with Kotlin?

I am trying to access the DVLA's Vehicle Enquiry API. Ive got this working with a really simple example in Python, but I really want to get this working in Kotlin using OKHttp so i can use the code in an Android app.
There seems to be some issue i cant figure out with the FormBody.Builder() and the vehicle registration that i put in the body. The error im getting from the API is...
{"errors":[{"status":"400","code":"ENQ108","detail":"Invalid format for field - vehicle registration number","title":"Bad Request"}]}
The DVLA's website shows a cUrl request example, I converted that to Python and it works perfectly, but i cant figure out what im missing when doing it with OKHttp/Kotlin.
You'll see in the Kotlin code i added a println(request) just so i could see what was being sent to the api. that request when printed contains the url + header, but NO body!
Kotlin Code - not working
import okhttp3.*
import java.io.IOException
private val client = OkHttpClient()
private val url_dvla = "https://driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles"
private val auth_dvla = "MY_API_KEY"
fun main(){
run(url_dvla)
}
fun run(url: String){
val requestBody = FormBody.Builder()
.add("registrationNumber", "AP08EKT")
.build()
val request = Request.Builder()
.url(url)
.post(requestBody)
.addHeader("x-api-key", auth_dvla)
.build()
println(request)
client.newCall(request).enqueue(object : Callback{
override fun onFailure(call: Call, e: IOException) {
TODO("Not yet implemented")
}
override fun onResponse(call: Call, response: Response) {
println(response.body?.string())
}
})
}

MultiPart File Upload with Quarkus / Kotlin

I am trying to build a multi-part file upload REST route in Quarkus (using Kotlin), but having issues with the route mapping.
From the Client side I am posting a form that contains a text value and a file value.
const formData = new FormData();
formData.append("text", text);
formData.append("file", files[0]);
fetch('http://localhost:8080/data', {
method: 'POST',
body: formData
})
From the serverside, I am trying to retrieve the values as follows.
class FormData(#FormParam("text") #PartType(MediaType.TEXT_PLAIN) var text:String,
#FormParam("file") #PartType(MediaType.APPLICATION_OCTET_STREAM) var file:InputStream)
#Path("/data")
class FormUploadResource {
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
fun upload(#MultipartForm form:FormData) {
println(form.text)
println(form.file)
}
}
However, when I execute the endpoint, I get a org.jboss.resteasy.spi.ReaderException: java.lang.NoSuchMethodException: error.
I have tried to make sure that the text and file parameters are correctly being received, and have inspected the payload coming in with the following code
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
fun upload(input:MultipartFormDataInput) {
var map = input.getFormDataMap()
map.entries.forEach {
println("""${it.key} - ${it.value}""")
if (it.value is List<InputPart>) {
it.value.forEach { ip ->
println(""" --- ${ip.getMediaType()} """ )
}
}
}
}
And it correctly says
text - [org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl$PartImpl#660c4317]
--- text/plain;charset=UTF-8
file - [org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl$PartImpl#3aee346]
--- application/octet-stream;charset=UTF-8
I assume there is something going wrong with the FormData class that RestEasy isn't automagically mapping to it. I have tried changing the type for "file" to be ByteArray and File, and they both fail also.
I have struggled to find Kotlin specific answers, so it is possible this is a Kotlin oddity also.
I just went through this issue, showing no logs at all. I managed to make it work, it seems that a empty constructor is required :
class FormData() {
#FormParam("text") #PartType(MediaType.TEXT_PLAIN)
var text: String? = null
#FormParam("file") #PartType(MediaType.APPLICATION_OCTET_STREAM)
var file: InputStream? = null
}
However I must still be missing something because
class FormData(
#FormParam("text") #PartType(MediaType.TEXT_PLAIN) var text: String?,
#FormParam("file") #PartType(MediaType.APPLICATION_OCTET_STREAM) var file: InputStream?
) {
constructor() : this(null, null)
}
enters in the method but doesn't init values
Edit: after testing secondary constructors and primary constructors like this working one,
class FormData
{
#FormParam("file")
#PartType(MediaType.APPLICATION_OCTET_STREAM)
var file: InputStream? = null
constructor() {
this.file = null
}
}
It seems that an EMPTY PRIMARY CONSTRUCTOR is required :)
Hope it helped !
I won't mark this answer as correct, as I am not happy with the solution, but it at least works.
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
fun upload(input:MultipartFormDataInput) {
val map = input.getFormDataMap()
val text = map.get("text")?.first()?.getBodyAsString() ?: ""
val file = map.get("file")?.first()?.getBodyAsString() ?: ""
println(form.text)
println(form.file)
}
As you can see, I am getting the data directly from the MultipartFormDataInput, rather than auto-constructing the object. Hopefully someone is able to shed some light on why this work around is needed, or whether a better solution is available.

kotlin: retrofit2 getting 404 url not found error

Getting Response{protocol=http/1.1, code=404, message=Not Found, url=https://test.test.com/service/one}
The url is correct as postman works fine.
I have tried looking into this error but most things come back with URL was in correct. and the error itself is vague.
code that starts it. the builder is a json string that is valid. I have tested it in postman.
CoroutineScope(Dispatchers.Default).launch {
val call = submitService.submitCarton(builder.toString())
Log.d("submit", "begining")
withContext(Dispatchers.Main) {
if (call.isSuccessful) {
Log.d("submit",call.body() as String)
} else {
Log.d("submit", "else....")
}
}
}
service factory:
fun makeSubmitService() : SubmitService{
val url = "https://test.test.com/service/"
return Retrofit.Builder().baseUrl(url)
.client(okHttpClient).addConverterFactory(GsonConverterFactory.create())
.build().create(SubmitService::class.java)
}
interface:
interface SubmitService {
#POST("one")
suspend fun submitCarton(#Body json: String): Response<myModel>
}
Expected results are a json response however I am not getting that far.
edit: I created a okhttpclient and did a request manual and I get a message 200 ok.
code for my test
val JSON = MediaType.parse("application/json; charset=utf-8")
val client = OkHttpClient()
val body = "some json"
val requestBody = RequestBody.create(JSON, body)
val request = Request.Builder()
.url("https://test.test.com/service/one")
.post(requestBody)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(request: Request, e: IOException) {
Log.e("test", e.toString())
}
#Throws(IOException::class)
override fun onResponse(response: Response) {
Log.d("test", response.toString())
}
})
Solved it myself.
Issue was dumb, retrofit2 was giving 404 even though the web service was returning a error message.
added
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.1'
private val interceptor = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
private val okHttpClient = OkHttpClient().newBuilder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build()
found out retrofit was sending a very unformatted string
"{ \"all my json filled with \" }"
instead of
{ json }
fixed it by adding
.addConverterFactory(ScalarsConverterFactory.create())
to my service factory
for anyone wondering why I am basically creating the json as a string instead of using a JSON object is because the service I talk to really really wants it to be in a very specific order which JSON just don't care about it however it wants it to look like JSON as well...

Retrofit respone null in Data Class

I'm a newbie about Kotlin. My first project is to consume a rest api. I already made that using retrofit. But I have a problem when I'm logging the response, my data class is null. I don't know where is the error.
My Rerofit Client
object RetrofitClient {
var retrofit: Retrofit? = null
fun getClient(baseUrl: String): Retrofit? {
if (retrofit == null) {
//TODO While release in Google Play Change the Level to NONE
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(100, TimeUnit.SECONDS)
.readTimeout(100, TimeUnit.SECONDS)
.build()
retrofit = Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}
My Interface
public interface ApiLoginService {
#POST("UserManagementCoreAPI/api/v1/users")
fun loginService(#Body request: RequestBody): Call<DataLogin>
}
object ApiUtils {
val BASE_URL = "------"
val apiLoginService: ApiLoginService
get() = RetrofitClient.getClient(BASE_URL)!!.create(ApiLoginService::class.java)
}
My class data
data class DataLogin (
#SerializedName("employeeId") val employeeId : String,
#SerializedName("fullName") val fullName : String,
#SerializedName("loginConfins") val loginConfins : String,
#SerializedName("branchId") val branchId : String,
#SerializedName("isActive") val isActive : String
)
Main Activity
mApiLoginService!!.loginService(requestBody).enqueue(object : Callback<DataLogin>{
override fun onResponse(call: Call<DataLogin>, response: Response<DataLogin>) {
if(response.isSuccessful()){
if(response.body().toString() == null){
Log.d(tag,"Null")
}else{
Log.d(tag,"Logging In " + response.body()!!)
progressBar.visibility = View.GONE
btn_submit.visibility = View.VISIBLE
startActivity(Intent(this#MainActivity, HomeActivity::class.java))
}
}else{
Toast.makeText(applicationContext, "Invalid username or password", Toast.LENGTH_LONG).show()
Log.d(tag,"Error " + response.errorBody().toString())
progressBar.visibility = View.GONE
btn_submit.visibility = View.VISIBLE
}
}
override fun onFailure(call: Call<DataLogin>, t: Throwable) {
progressBar.visibility = View.GONE
btn_submit.visibility = View.VISIBLE
}
})
My Respone Log
message: Logging In DataLogin(employeeId=null, fullName=null, loginConfins=null, branchId=null, isActive=null)
I don't know where is the error and why my data is null. If the response succeeds is still gives me null.
This is a postman example
You have an issue with your schema , Your DataLogin class is different of your postman schema , Retrofit is waiting for : fullName, isActive ...., and the response is : header , data .. , you have to create class that contains header as variable of type Header(errors:List<AnotherClass>), data as variable of type Data(data(List<DataLogin>),totalRecord:Int), i would suggest if you use helper website like JSON to Class , parse your postman response there , and he will give you your correct response class but it's will be in java , you have to rewrite the code yourself of just copy paste in android studio and he will convert the code to Kotlin for you. (in the web site , check Source type: JSON)
You have to match the json structure with your data classes if you do not provide a custom adapter to Gson. So if you want to have a result, maybe something like this will work:
data class Response(
#SerializedName("headers") val headers: List<Any>,
#SerializedName("data") val data: Data
)
data class Data(
#SerializedName("data") val data: List<DataLogin>,
#SerializedName("totalRecord") val totalRecord: Int
)
data class DataLogin (
#SerializedName("employeeId") val employeeId : String,
#SerializedName("fullName") val fullName : String,
#SerializedName("loginConfins") val loginConfins : String,
#SerializedName("branchId") val branchId : String,
#SerializedName("isActive") val isActive : String
)
You need to return a Response object from your retrofit call.
Also a few tips about kotlin, Gson works well for Java, but it has some issues with kotlin (about null safety). I use Moshi when the project language is kotlin and it works well with it.
Try to avoid using !! in kotlin because it will cause RuntimeException. There are other ways of checking null and to protect your code from RuntimeExceptions.