Hii guys so I'm working on a microservice I'm usin...
# ktor
a
Hii guys so I'm working on a microservice I'm using httpclient to plug into the UberApi and I'm getting results in the desired route in the localhost Now i need to plug it to my ktorservice so I can use a Post request from the Android end and get desired results on mobile client
h
you are not asking a specific question
😁 1
a
Okay i need help on how i can make the data i got available to the android end. My idea of how this works is that you need a ktor client to plug into the UberApi which i have done and i need to plug it to my ktor server to make it available Making it available is what i dont know how to do @Hamza
r
Make an endpoint : ‱ call Uber API ‱ transform data received to your own ‱ respond to client Android with your data ?
a
Yeah I have called the UberApi Transforming data can be done in what ways please Its my first time doing backend @Rémy
r
No problem, I’m not an expert too (Android developer first 🙂). You made like a middleware, I did that too, between a third api and you client. I did things in the endpoint method (my previous message). Do you have small example code to show ?
a
Copy code
val client = HttpClient()
val data = <http://client.post|client.post><String>(requestURL) {
    header("Authorization", Auth.authKey)
    body =
        """{
            |"pickup_stop": {"lat": ${start.lat}, "lng": ${start.lng}}, 
            |"destination_stops": [{"lat": ${end.lat}, "lng": ${end.lng}}], 
            |"payment_method_id": "${paymentMethod}", 
            |"payment_method_type": "default", 
            |"timezone": "${timeZone}", 
            |"preliminary": "true"
        |}""".trimMargin()
}
client.close()
return data
Copy code
get("/BoltRides") {
    call.respondText(getBoltRides(location(51.5073509, -0.1277583), location(51.5073509, -0.1277583)))
}
@Rémy
This is how i'm getting for bolt
the route is in application.Kt
r
Do you have something in return of your getBoltRides first ?
a
I can get data in my postman, returns a largeset of data altogether
@Rémy
r
Ok, I think your mapping, or something else is messed up. Are you using the native Ktor client (I ask because I use a different one to consume others APIs, a habit from Android => OkHttp) ?
a
yes
Copy code
import io.ktor.client.HttpClient
@Rémy
r
Okay I’m looking documentation.
a
Copy code
<http://httpClient.post|httpClient.post><ClassName>
can u replace the className with a data class ?
r
It was my first expectation, but did you log you api call to handle error first ?
Maybe, your authentication isn’t well implemented.
And yes, a (data) class as dto is a better practice.
a
@arjun will that help me if i change it to a data class?
r
You need the call logs first. To debug properly your problem.
a
okay, first time hearing about that. you mean log like android?
a
1. Cast the response to DTO, 2. have a try catch to see if u are getting any exception 3. better to create a request DTO and assign the instance to body rather than having a JSON there. 4. Set content-type header if its not picking JSON by default
r
a
okay thanks does that mean I dont really need a repository pattern or Interface? @arjun @Rémy
r
It means you have to found the root cause first 🙂 dto instead of a String is a good practice. But, to debug properly, you need the error log 😉 Step by step 😄
Let me now if you found the error.
a
mmm, i'm not getting any errors i'm getting my desired results are you saying there might be potential errors
?
@Rémy
r
Alright you received yours data isn’t it ?
a
yes
r
So, what’s the problem ? Your client doesn’t get the response ?
a
or I guess i'm not mean to use GET in the application.kt? i only used that to see if i could get the result the data is a verylarge one and I dont need most of the info its sending, is there a way i can streamline it so I can get it in my client?
r
If you want just some informations, you have to make a data mapping on a smaller object who fit your needs.
An interface / class / data class map the API response, then, you can make an other object with just some properties. Then, you send it to your client.
a
@Ayodele how are u getting the data now? what solved the problem ?
➕ 1
r
Make the mapping on the backend side. Client doesn’t need too much infos.
As I understand, problem wasn’t retrieving api informations but informations mapping, isn’t it @Ayodele?
a
@arjun @Rémy i've been getting the data what is confusing me is how to expose this to the client because this backend service will be hosted what i want basically is to be able to call myapp.herokuapp.com/boltride through a POST request from an adnroid app and get my data the way I'm getting it now
@arjun
with less data of course
r
Like @arjun said, your data response needs to be a class (data), then use it’s properties / data to make your own object to send to Android client.
Copy code
val data = <http://client.post|client.post><UberDataDto>(requestURL) { //...
https://ktor.io/clients/http-client/quick-start/responses.html You have to deserialized the response into an object. https://ktor.io/clients/http-client/features/json-feature.html <-
a
whew, Okay thanks would have been nice if someone had a public repo or something
r
I think but I don’t have link. Do you have the Uber endpoint definition, to be able to create the DTO ?
a
i'm sorry definition?
@Rémy
r
Each endpoint has a response definitions, normally it’s in the Uber API document. Like /getUberDriver => 200 : { “id”: string, “name”: string, age: number, ... }
a
Copy code
fun getRides(request: PickupRequest): PickupResponse {
        return try {
            val response = <http://httpClient.post|httpClient.post><PickupResponse> {
                header("Content-Type", ContentType.Application.Json.toString())
                url(requestUrl)
                body = request
            }
            response
        } catch(e: Exception) {
            logger.error(e.message, e)
            null
        }
    }
👏 1
a
hmm, this would help
thanks @Rémy @arjun
🙂 1
hi @Rémy @arjun will this work
Copy code
data class BoltResponse (
     val message : String,
    val city : String,
    val searchCategories : List<Rides>
):Serializable
message. city and searchCategories is what i'm getting searchCategories is a list
r
I don’t know what the service send. I suppose it’s alright 🙂
a
Yeah
🙂 1
hi @Rémy @arjun I'm getting this error
ERROR Application - Unhandled: GET - /BoltRides
java.lang.IllegalStateException: Request cannot be executed; I/O reactor status: STOPPED
I used a logger
Copy code
get("/BoltRides") {
    call.respond(getBoltRides(location(51.5073509, -0.1277583), location(51.5073509, -0.1277583)))
}
this is how i'm calling it after I started using a DTO i coukdnt use respond text any longer
r
If you extract the method from the response and put result data in an object. What’s do you reveived ? What’s the return data type ?
You have to serialized you object 🙂
a
how do I do that
my function has a return type of the DTO class
r
With Gson, or Jackson ?
a
just like arjun wrote yesterday
Gson
r
Hum, normally Ktor can handle serialization on the fly, but I need to look the documentation.
You have to configure Gson for server side response. And if respond with a Class, Ktor automatically serialized it to Json.
a
I
Copy code
install(ContentNegotiation) {
    gson {
    }
}
I have that in my App.kt
r
Yeap, and it didn’t work ?
a
nah must I call client.close() after finishing request?
r
Try to remove this.
Is it mentioned in the documentation ?
a
if i remove it thers's another error
ERROR Application - Unhandled: GET - /BoltRides
io.ktor.client.call.NoTransformationFoundException: No transformation found: class <http://kotlinx.coroutines.io|kotlinx.coroutines.io>.ByteBufferChannel
r
@Ayodele I will make a small example of what you want to do into a small github repo 🙂 The basics of consume a third api and deserialized / Serialized data to use.
a
Thanks, that will be really appreciated
Thanks a lot
r
🙂
Just give me ~ 30 min
a
Alright
r
Okay I push it to Github.
a
url?
r
2 secs
Really simple case.
a
Thanks alot
hey I figured how to deserialize it Thanks
its working now
👏 1
r
You understood the concept, and it’s the main goal 🙂
👍 1
In my exampel I forget to close de client 😉
If you execute the call inside a lambda, it’s handle by default.
a
yeah, I did that
@Rémy please if i wanna write unit test for a function like this
Copy code
fun getRides(request: PickupRequest): PickupResponse {
        return try {
            val response = <http://httpClient.post|httpClient.post><PickupResponse> {
                header("Content-Type", ContentType.Application.Json.toString())
                url(requestUrl)
                body = request
            }
            response
        } catch(e: Exception) {
            logger.error(e.message, e)
            null
        }
    }
how do I go about it? I have never written unitTests
r
Don’t write unit test related to webservice. I think it’s more reliable to write unit test for your business logic (e.g. dto -> your own object, etc...). So, you can mock / fake a webservice response with a local json, and test what you make with data. I’m not an expert for test related web services.
a
more like when a create a repository?
r
Test how you manage your data inside your application, and what you send to the client.
a
Alright
Thanks
😉 1
a
for DB it makes sense to write integration tests. for a client, u just need to mock the response and test any custom logic (like u wanted to create a custom DTO from a big object)
👍 1
a
Hi @Rémy please how to I log in ktor like in android LOG.d()
r
At this time I never used it, but I place often some println(). You can look at this. Maybe, @arjun had better option / opinion ?
a
Alright
a
Copy code
install(CallLogging) {
    level = <http://Level.INFO|Level.INFO>
}
👍 1
a
Thanks @arjun
a
a
@arjun @Rémy dplease help i'm getting this error
java.io.IOException: Broken delimiter occurred
Hi guys, please i just noticed that my server doesnt receive json requests from android client it only accepts form parameters
r
What’s your endpoint ?
a
could this be this issue?
Copy code
val signUpParameters = call.receive<parameters>()
what do people use normally?
call.receive<DTO>()
?
I think you want to receive an object. Not a form.
a
yeah
Thanks
r
😉
a
hi @Rémy please I have a list, bascially an array from an external Api and I want to map the properties i to my own properties in another list so it returns something like List<MyDTO>
please help
r
Create a function to map your dto list to your own data.
a
did that it was showing empty array in my response and I'm receiving response from the external Api
Copy code
override suspend fun getResponse(start: Location, end: Location): List<MyDTOResponse>? {
    val myResponse = listOf< MyDTOResponse>()
    val apiRes = getApiRes(start, end)!!.data.rideCategories

}
i did somthing like this
and I tried to equate the properties of myResponse to my apiRes MyDTOResponse returrned an empty array
r
I don’t understand correctly your flow. You retrieve some data from API (a list), and you want to make a new list with it ?
a
yeah, exactly
r
Just after you retrieve your api list, then map it to your own objects.
apiRes.forEach { category -> newList.add(MyObject.fromDto(category)) } ? Something like that ?
a
whats MyObject.fromDTO?
r
Your object which you want to use đŸ€·â€â™‚ïž
It’s not working ?
a
i cant call MyObject, its also a list do i have to loop?
I know forEach is a loop
got it
i used yourmethod
thanks
r
😉
a
Hi @arjun @Rémy Please have you used Jwt before? I'm trying to use postman for my requests and i noticed postman added a previous;y gotten response, and added it as the Bearer so it was giving me this error
Error: Invalid character in header content ["Authorization"]
do you know what the issue might be?
r
No idea 😕
a
can u be more specific ? for authorization u need a Bearer token. usual format is
Bearer JwtToken
a
yes
a
do u need authorization or not ?
a
mine looks like this
I need authorization
a
do you know what is Authorization ? and what you are trying to achieve ?
and do you know what is JWT ?
➕ 1