Can't use RapidApi with Retrofit - android

I'm new with Retrofit and I'm trying to use Google Translate Api from RapidApi with Retrofit but i can't convert okhttp code snippet to retrofit
This is the sample code snippet for Post request working with OkHttp:
val client = OkHttpClient()
val mediaType = MediaType.parse("application/x-www-form-urlencoded")
val body = RequestBody.create(mediaType, "q=Hello%2C%20world!&target=es")
val request = Request.Builder()
.url("https://google-translate1.p.rapidapi.com/language/translate/v2")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("Accept-Encoding", "application/gzip")
.addHeader("X-RapidAPI-Host", "google-translate1.p.rapidapi.com")
.addHeader("X-RapidAPI-Key", API_KEY)
.build()
val response = client.newCall(request).execute()
i want to make same request with Retrofit in android
This is my api interface:
interface TranslatorApi {
#Headers(
"content-type: application/x-www-form-urlencoded",
"Accept-Encoding: application/gzip",
"X-RapidAPI-Host: google-translate1.p.rapidapi.com",
"X-RapidAPI-Key: API_KEY
)
#POST("translate/v2")
suspend fun translate(
#Body q: String,
#Query("target") target: String,
#Query("source") source: String
): Response<GoogleTranslateObject>
}

Related

Android HTTP Headers with API

What are headers used for if I want to do a post request & response ?
How is it possible to "save" token there ?
I can't find any good explanation about it.
you can use Retrofit to call api and store token into shared preferences and add common headers to OkhttpClient
val prefs = Prefs.getInstance();
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor { chain ->
val original = chain.request()
val request = original.newBuilder()
.header("Authorization", prefs.token)
.header("Accept", "application/json")
.method(original.method, original.body)
.build()
chain.proceed(request)
}
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
httpClient.addInterceptor(interceptor)
val client = httpClient.build()
and make Retrofit object like this
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(
GsonConverterFactory.create(
GsonBuilder().setPrettyPrinting().create()
)
)
.client(client).build()

OKHttpClient Response - bad request

I get a response - Bad Request when making an api request using OKHttpClient. Can someone please help? Response Code - 400
https://sendgrid.com/docs/API_Reference/api_v3.html
val policy = StrictMode.ThreadPolicy.Builder()
.permitAll().build()
StrictMode.setThreadPolicy(policy)
val client = OkHttpClient()
val body: RequestBody = RequestBody.create(
"application/json".toMediaTypeOrNull(),
"{\"list_ids\":[\"a7aab3b0-\"],\"contacts\":[{\"email\": \"" + userEmail + "\"}]}"
)
val request: Request = Request.Builder()
.url("https://api.sendgrid.com/v3/marketing/contacts")
.put(body)
.addHeader("authorization", "Bearer SG.7LPq")
.addHeader("content-type", "application/json")
.build()
val response = client.newCall(request).execute()
It looks like your keys don't match the case being used in the API docs, they are capitalised. Also have you tried checking that toMediaTypeOrNull() is able to format that as JSON? It's difficult to tell how it will handle those slashes but they shouldn't be needed.

OkHttp Websockets - Add a body when connecting to websocket

I am using the okHttp websocket library and I am successfully connecting to my websocket server, but currently I am only getting the connection id when connected. I want to send some extra info in the body, but I don't know how to add it using okHttp
Request request = new Request.Builder()
.url("wss://mywebsocketurl.com")
.build();
I have tried
RequestBody requestBody = new FormBody.Builder()
.add("camera_id", "e9502c54-927c-4639-a94f-8d03149c9c62")
.build();
Request request = new Request.Builder()
.url("wss://mywebsocketurl.com")
.method("POST", requestBody)
.build();
Request request = new Request.Builder()
.url("wss://mywebsocketurl.com")
.post(requestBody)
.build();
But it keeps returning
java.lang.IllegalArgumentException: method GET must not have a request body.
I know it's too late to answer.
The url should anyways be GET only. So i made the connection and on onOpen callback function, i send the body. It worked.
private fun initializeSocket(url: String) {
val request: Request = Request.Builder().url(url).build()
val listener = WebSocketListener()
webSocket = client!!.newWebSocket(request, listener)
client?.dispatcher()?.executorService()?.shutdown()
}
private class WebSocketListener : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response?) {
val content = "{\n" +
" \"messageType\": \"INIT_CONNECTION\"\n" +
"}"
webSocket.send(content)
}
...
}

Retrofit headers interceptor does not change header

I have android app with few api calls. I noticed that every call has
#Headers("Content-Type: application/json") annotation in ApiService so I decided remove annotation and add header via interceptor to all requests:
val headers = { chain: Interceptor.Chain ->
val request = chain.request().newBuilder()
.addHeader("Content-Type", "application/json")
.build()
chain.proceed(request)
}
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(headers)
.addInterceptor(logging)
.build()
val customGson = GsonBuilder()
.registerTypeAdapter(NameValuesList::class.java, NamesValuesListConverter())
.create()
val retrofit = Retrofit.Builder()
.baseUrl("http://www.$fullDomain")
.addConverterFactory(GsonConverterFactory.create(customGson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build()
service = retrofit.create(ApiService::class.java)
But after that server return error on api call.
In logs I see that when I have explicit #Headers() annotation:
D/OkHttp: Content-Type: application/json
And after replace it with interceptor:
D/OkHttp: Content-Type: application/json; charset=UTF-8
I tried to change interceptor to this one:
val headers = { chain: Interceptor.Chain ->
val request = chain.request().newBuilder()
.headers(Headers.of(mutableMapOf("Content-Type" to "test")))
.build()
chain.proceed(request)
}
But I still see this in log:
D/OkHttp: Content-Type: application/json; charset=UTF-8
So looks like my interceptor does not apply or overridden. How to fix it?
UPD. I found the reason: when I add GsonConverterFactory it automatically add header Content-Type: application/json; charset=UTF-8. Are there any way to avoid it without implementing custom ConverterFactory?
as documentation says :
"Note: Headers do not overwrite each other. All headers with the same name will be included in the request."
refer to retrofit Headers
You can check if header exist.
val headers = { chain: Interceptor.Chain ->
val request = chain.request().newBuilder()
if(chain.request().header("Content-Type") == null){
request.addHeader("Content-Type", "application/json")
}
chain.proceed(request.build())
}
Try this
chain.request().newBuilder().removeHeader("Content-Type") .headers(Headers.of(mutableMapOf("Content-Type" to "test"))) .build()

How to specify Get-Request encoding (Retrofit + OkHttp)

I'm using Retrofit2 + OkHttp3 in my Android app to make a GET - Request to a REST-Server. The problem is that the server doesn't specify the encoding of the JSON it delivers. This results in an 'é' being received as '�' (the Unicode replacement character).
Is there a way to tell Retrofit or OkHttp which encoding the response has?
This is how I initialize Retrofit (Kotlin code):
val gson = GsonBuilder()
.setDateFormat("d.M.yyyy")
.create()
val client = OkHttpClient.Builder()
.build()
val retrofit = Retrofit.Builder()
.baseUrl(RestService.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
val rest = retrofit.create(RestService::class.java)
PS: The server isn't mine. So I cannot fix the initial problem on the server side.
Edit: The final solution
class EncodingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
val mediaType = MediaType.parse("application/json; charset=iso-8859-1")
val modifiedBody = ResponseBody.create(mediaType, response.body().bytes())
val modifiedResponse = response.newBuilder()
.body(modifiedBody)
.build()
return modifiedResponse
}
}
One way to do this is to build an Interceptor that takes the response and sets an appropriate Content-Type like so:
class ResponseInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
val modified = response.newBuilder()
.addHeader("Content-Type", "application/json; charset=utf-8")
.build()
return modified
}
}
You would add it to your OkHttp client like so:
val client = OkHttpClient.Builder()
.addInterceptor(ResponseInterceptor())
.build()
You should make sure you either only use this OkHttpClient for your API that has no encoding specified, or have the interceptor only add the header for the appropriate endpoints to avoid overwriting valid content type headers from other endpoints.
class FixEncodingInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
MediaType oldMediaType = MediaType.parse(response.header("Content-Type"));
// update only charset in mediatype
MediaType newMediaType = MediaType.parse(oldMediaType.type()+"/"+oldMediaType.subtype()+"; charset=windows-1250");
// update body
ResponseBody newResponseBody = ResponseBody.create(newMediaType, response.body().bytes());
return response.newBuilder()
.removeHeader("Content-Type")
.addHeader("Content-Type", newMediaType.toString())
.body(newResponseBody)
.build();
}
}
and add to OkHttp:
builder.addInterceptor(new FixEncodingInterceptor());
This post is old but I found a solution that works for me in Kotlin (the answer of #BryanHerbst didn't quite worked for me)
class EncodingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
var encodedBody = ""
val encoding = InputStreamReader(
response.body?.byteStream(),
Charset.forName("ISO-8859-1")
).forEachLine {
encodedBody += it
}
return response.newBuilder()
.addHeader("Content-Type", "application/xml; charset=utf-8")
.body(encodedBody.toResponseBody())
.build()
}
}

Categories

Resources