why i am not getting any response - android

data class NewsResponse(
val articles: List<Article>,
val status: String,
val totalResults: Int
)
data class Source(
val id: String,
val name: String
)
data class Article(
val author: String,
val content: String,
val description: String,
val publishedAt: String,
val source: Source,
val title: String,
val url: String,
val urlToImage: String
)
object RetrofitHelper {
fun getInstances():Retrofit{
return Retrofit.Builder()
.baseUrl("https://newsapi.org/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
interface NewsService {
#GET("v2/everything?")
suspend fun getNews(#Query("country")country:String,#Query("page")page:Int,#Query("apiKey")apiKey:String):Response<NewsResponse>
}
This below code is written on MainActivity
val newsservice=RetrofitHelper.getInstances().create(NewsService::class.java)
GlobalScope.launch(Dispatchers.IO) {
val result=newsservice.getNews(country,page, apiKey)
if(result.isSuccessful){
Toast.makeText(this#MainActivity,"HEllo World",Toast.LENGTH_LONG).show()
val list=result.body()!!.articles
list.forEach {
Log.d(debug,it.source.id)
}
}
}

I corrected my mistake #Query("country") this was wrong i have to use #Query("q") thats my result giving null list

Related

how to get data from rest api using retrofit kotlin android

I am trying to get data from rest api using retrofit on Android app.
I am trying to reach the data structured below;
sections -> items -> venue -> id (Unique id of the venue)
sections -> items -> venue -> name (Name of the venue)
sections -> items -> venue -> short_description (Description of the venue)
I can reach to the sections but not the data under the section.
data class VenueModel(
val created: Created,
val expires_in_seconds: Int,
val filtering: Filtering,
val name: String,
val page_title: String,
val sections: List<Section>,
val show_large_title: Boolean,
val show_map: Boolean,
val sorting: SortingX,
val track_id: String
)
data class Section(
val items: List<Item>,
val link: LinkX,
val name: String,
val template: String,
val title: String
)
data class Item(
val description: String,
val filtering: FilteringX,
val image: Image,
val link: Link,
val overlay: String,
val quantity: Int,
val quantity_str: String,
val sorting: Sorting,
val template: String,
val title: String,
val track_id: String,
val venue: Venue
)
data class Venue(
val address: String,
val badges: List<Badge>,
val categories: List<Any>,
val city: String,
val country: String,
val currency: String,
val delivers: Boolean,
val delivery_price: String,
val delivery_price_highlight: Boolean,
val delivery_price_int: Int,
val estimate: Int,
val estimate_range: String,
val franchise: String,
val id: String,
val location: List<Double>,
val name: String,
val online: Boolean,
val price_range: Int,
val product_line: String,
val promotions: List<Any>,
val rating: Rating,
val short_description: String,
val show_wolt_plus: Boolean,
val slug: String,
val tags: List<String>
)
this is api service interface;
interface APIService {
#GET("v1/pages/restaurants?lat=60.170187&lon=24.930599")
fun getVenues(#Query("lat") locationLatitude: String, #Query("lon") locationLongitude: String) : Call<VenueModel>
}
And this is main activity;
class MainActivity : AppCompatActivity() {
var locationLatitude = "60.170187"
var locationLongitude = "24.930599"
lateinit var venueSearchListSection: List<Section>
lateinit var venueSearchListItem: List<Item>
lateinit var venueSearchListVenue: List<Venue>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
venueSearchListSection = ArrayList<Section>()
venueSearchListItem = ArrayList()
venueSearchListVenue = ArrayList()
fetchDataFromApi()
}
private fun fetchDataFromApi(){
//venue results from api
val retrofitVenueSearch = Retrofit.Builder()
.baseUrl("https://restaurant-api.wolt.com/")
.addConverterFactory(GsonConverterFactory.create()).build()
val apiVenueSearch = retrofitVenueSearch.create(APIService::class.java)
apiVenueSearch.getVenues(locationLatitude, locationLongitude).enqueue(object :
Callback<VenueModel> {
override fun onResponse(
call: Call<VenueModel>,
response: Response<VenueModel>
) {
venueSearchListSection = response.body()?.sections ?: venueSearchListSection
//I have the problem here. I can get the data in venueSearchListSection
//arraylist but I can not reach the data inside it.
}
override fun onFailure(call: Call<VenueModel>, t: Throwable) {
t.message?.let { Log.e("venue", it) }
}
})
}
}
Thanks for your helps in advance.

What is the right way to post with retrofit 2 and moshi

I've been trying to make a POST with Retrofit 2 and Moshi but I've been unable to get it to work.
My data classes look like this:
data class Order(
val items: List<Item>?,
val customerName: String,
val customerPhoneNo: String,
val customerAddress: String,
val note: String
)
data class Item(
val productUid: String,
var quantity: Int
)
The interface looks like this
interface ProductService {
#POST("/api/order/saveorder")
suspend fun postProds(
#Field("customerName") customerName: String,
#Field("customerPhoneNo") customerPhone: String,
#Field("customerAddress") address: String,
#Field("note") customerNote:String,
#Field("items") orderItems: List<Item>
): Response<Order>
#GET("/api/product/allproducts")
suspend fun getProds(): Response<List<ProdsItem>>
}
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
object Network {
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi)
.asLenient()
)
.build()
object ProdsApi {
val retrofitService: ProductService by lazy {
retrofit.create(ProductService::class.java)
}
}
}
The postProds fun is called like this:
suspend fun sendOrder(order: Order) {
withContext(Dispatchers.Main){
try {
val orderResponse = Network.ProdsApi.retrofitService.postProds(
order.customerName,
order.customerPhoneNo,
order.customerAddress,
order.note,
order.items )
}
catch (e: Exception) {
Timber.e(e)
}
}
}
Trying to POST this way keeps yielding this response:
Response{protocol=h2, code=400, message=, url=
However, I tried converting the Order object to json directly in my viewModel as follows:
val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val jsonAdapter: JsonAdapter<Order> = moshi.adapter(Order::class.java)
val jsonString = jsonAdapter.toJson(customerOrder)
Timber.d(jsonString)
I then tested the generated jsonString on Postman and got a 200 response.
I need some help figuring out what I'm doing wrong in my code, please.
In postman, you are sending data in the body of the request. But in your code, it is going as key-value params. Try to send it in the body from your code. Try below snippet.
Update your Order Data class:
#JsonClass(generateAdapter = true)
data class Order(
#Json(name = "items")
val items: List<Item>?,
#Json(name = "customerName")
val customerName: String,
#Json(name = "customerPhoneNo")
val customerPhoneNo: String,
#Json(name = "customerAddress")
val customerAddress: String,
#Json(name = "note")
val note: String
)
#JsonClass(generateAdapter = true)
data class Item(
#Json(name = "productUid")
val productUid: String,
#Json(name = "quantity")
var quantity: Int
)
Now the ProductService Interface:
interface ProductService {
#POST("/api/order/saveorder")
suspend fun postProds(
#Body request: Order
): Response<Order>
#GET("/api/product/allproducts")
suspend fun getProds(): Response<List<ProdsItem>>
}
Now Pass the request object in your function call:
suspend fun sendOrder(order: Order) {
withContext(Dispatchers.Main){
try {
val orderResponse = Network.ProdsApi.retrofitService.postProds(order)
}
catch (e: Exception) {
Timber.e(e)
}
}
}

How to make post request with retrofit + moshi

I'm trying to make a post with retrofit and moshi but keep getting the error mess
com.squareup.moshi.JsonDataException: Expected BEGIN_OBJECT but was STRING at path $
I can't seem to understand why this is so. This is a sample of the json tested on postman:
{
"customerName": "Name",
"customerPhoneNo": "090000000",
"customerAddress": "Address",
"note": "Please",
"items" : [{
"productUid": "5633e1f1-8b00-46de-b73e-43799245a4e8",
"quantity" : "3"
},{
"ProductUid": "fca3ffb1-0130-4e47-b499-721d046c1e32",
"Quantity" : "5"
},
{
"ProductUid": "6a7f3e24-03ff-408a-b67e-8530d411390c",
"Quantity" : "2"
}]
}
My data classes are set up like so:
#Parcelize
data class Order(
val items: List<Item>?,
val customerName: String,
val customerPhoneNo: String,
val customerAddress: String,
val note: String
) : Parcelable
and
#Parcelize
data class Item(
val productUid: String,
var quantity: Int
) : Parcelable
Service utils look like:
interface ProductService {
#Headers("Content-Type: application/json")
#POST("/api/order/saveorder")
suspend fun postProds(#Body order: Order
): Response<Order>
#GET("/api/product/allproducts")
suspend fun getProds(): Response<List<ProdsItem>>
}
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
object Network {
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi)
.asLenient()
)
.build()
object ProdsApi {
val retrofitService: ProductService by lazy {
retrofit.create(ProductService::class.java)
}
}
}
The sendOrder function is set up like so:
suspend fun sendOrder(order: Order) {
withContext(Dispatchers.Main){
try {
val orderResponse = Network.ProdsApi.retrofitService.postProds(
order )
}
catch (e: Exception) {
Timber.e(e)
}
}
}
The GET request works perfectly.
Any help on this would be appreciated please.
In your Item Data Class you are using quantity as an Int but if you see the Postman JSON response it is a String.
So your class should be like:
data class Item(
#Json(name = "productUid")
val productUid: String?,
#Json(name = "quantity")
var quantity: String
)
Also as I see the key in your JSON response are written in two different ways.
For example your "Product ID" is written as "productUid" in one of the object and is written as "ProductUid" in another object.
So your complete Item Data Class should more look like this :
data class Item(
#Json(name = "productUid")
val productUid: String?,
#Json(name = "ProductUid")
val productUid: String?,
#Json(name = "quantity")
val quantity: String?,
#Json(name = "Quantity")
val quantity: String?
)
Add to app/build.gradle
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
Refactor your data class
check the key in your item and replace with right one
if productUid or ProductUid
quantity or Quantity
#JsonClass(generateAdapter = true)
data class Item(
#Json(name = "productUid")
val productUid: String,
#Json(name = "quantity")
var quantity: String
)
#JsonClass(generateAdapter = true)
data class Order(
#Json(name = "items")
val items: List<Item>,
#Json(name = "customerName")
val customerName: String,
#Json(name = "customerPhoneNo")
val customerPhoneNo: String,
#Json(name = "customerAddress")
val customerAddress: String,
#Json(name = "note")
val note: String
)
and try it again

Make Kotlin Serializer work with Retrofit

I cant make Kotlin Serializer work with Retrofit. I am using com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.5.0 package along with Retrofit.
data classes
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
#Serializable
data class YelpSearchResult(
#SerialName("total") val total: Int,
#SerialName("businesses") val restaurants: List<YelpRestaurant>
)
data class YelpRestaurant(
val name: String,
val rating: Double,
val price: String,
#SerialName("review_count") val numReviews: Int,
#SerialName("distance") val distanceInMeters: Double,
#SerialName("image_url") val imageUrl: String,
val categories: List<YelpCategory>,
val location: YelpLocation
) {
fun displayDistance(): String {
val milesPerMeter = 0.000621371
val distanceInMiles = "%.2f".format(distanceInMeters * milesPerMeter)
return "$distanceInMiles mi"
}
}
data class YelpCategory(
val title: String
)
data class YelpLocation(
#SerialName("address1") val address: String
)
service interface
public interface YelpService {
#GET("businesses/search")
fun searchRestaurants(
#Header("Authorization") authHeader: String,
#Query("term") searchTerm: String,
#Query("location") location: String): Call<YelpSearchResult>
}
The Activity
val contentType = MediaType.get("application/json")
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(Json.asConverterFactory(contentType))
.build()
val yelpService = retrofit.create(YelpService::class.java)
yelpService.searchRestaurants("Bearer ${api_key}",
"Something", "Some Location").enqueue(
object: Callback<YelpSearchResult> {
override fun onFailure(call: Call<YelpSearchResult>, t: Throwable) {
Log.d("MainActivity", "err ${t}")
}
override fun onResponse(call: Call<YelpSearchResult>, response: Response<YelpSearchResult>) {
Log.d("MainActivity", "succ ${response}")
}
}
)
When Running, the thrown exception is,
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.xx.xx/com.xx.xx.MainActivity}:
java.lang.IllegalArgumentException: Unable to create converter for
class com.xx.xx.YelpSearchResult
Unable to create converter for class com.xx.xx.YelpSearchResult
for method YelpService.searchRestaurants
Caused by: kotlinx.serialization.SerializationException: Can't locate
argument-less serializer for class YelpSearchResult. For generic
classes, such as lists, please provide serializer explicitly.
What am I doing wrong? thanks for any directions.
You forgot to put #Serializable annotation on top of YelpRestaurant
#Serializable
data class YelpRestaurant {
...
}
YellCategory and YelpLocation should also have the annotation at place.
Add Serializable in your data classes
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
#Serializable
data class YelpSearchResult(
#SerialName("total") val total: Int,
#SerialName("businesses") val restaurants: List<YelpRestaurant>
)
#Serializable
data class YelpRestaurant(
val name: String,
val rating: Double,
val price: String,
#SerialName("review_count") val numReviews: Int,
#SerialName("distance") val distanceInMeters: Double,
#SerialName("image_url") val imageUrl: String,
val categories: List<YelpCategory>,
val location: YelpLocation
) {
fun displayDistance(): String {
val milesPerMeter = 0.000621371
val distanceInMiles = "%.2f".format(distanceInMeters * milesPerMeter)
return "$distanceInMiles mi"
}
}
#Serializable
data class YelpCategory(
val title: String
)
#Serializable
data class YelpLocation(
#SerialName("address1") val address: String
)

GSON is not mapping values with data class in kotlin

Hi I am using gson library to map values of response to model. I am doing it like this but it is not mapping values of response to model. I am getting list of 50 models but values in it is zero.
#Provides
#Singleton
fun provideRestApiHelper(
okHttpClient: OkHttpClient,
gson: Gson,
rxJava2CallAdapterFactory: RxJava2CallAdapterFactory): RestApi {
val builder = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addCallAdapterFactory(rxJava2CallAdapterFactory)
.addConverterFactory(GsonConverterFactory.create(gson))
val retrofit = builder.client(okHttpClient).build()
return retrofit.create(RestApi::class.java)
}
RestApi.kt
interface RestApi {
#GET(ApiEndPoint.ENDPOINT_GITHUB_JOBS)
fun getJobsApiCall(): Observable<List<JobsResponse>>
}
ApiHelperImpl.kt
class ApiHelperImpl #Inject constructor(private val restApi: RestApi) : ApiHelper {
override fun getJobsApiCall(): Observable<List<JobsResponse>> {
return restApi.getJobsApiCall()
}
}
JobsResponse.kt
data class JobsResponse(
#field:SerializedName("company_logo")
val companyLogo: String?,
#field:SerializedName("how_to_apply")
val howToApply: String?,
#field:SerializedName("created_at")
val createdAt: String?,
#field:SerializedName("description")
val description: String?,
#field:SerializedName("location")
val location: String?,
#field:SerializedName("company")
val company: String?,
#field:SerializedName("company_url")
val companyUrl: String?,
#field:SerializedName("id")
val id: String?,
#field:SerializedName("title")
val title: String?,
#field:SerializedName("type")
val type: String?,
#field:SerializedName("url")
val url: String?
) : BaseResponse()
I am calling this API https://jobs.github.com/positions.json. Does anyone know what could be the issue ?
That's because you rely on auto-converted java code
remove #field:SerializedName changed it to #SerializedName
don't put them in to primary constructor
define them like this:
data class JobsResponse(){
#SerializedName("company_logo")
val companyLogo: String? = null
....
}

Categories

Resources