OkHttp Websockets - Add a body when connecting to websocket - android

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)
}
...
}

Related

Can't use RapidApi with Retrofit

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>
}

Android , Okhttp - how to add subprotocol to websocket connection

in my app I'm using OkHttp to establish Websocket connection. Here's method to start connection :
private fun start(token: String, id: String, url: String) {
val request: Request = Request
.Builder()
.url(url)
.header("Authorization", token)
.header("iD", id)
.build()
val listener = ValidationWebSocketListener
client.newWebSocket(request, listener)
client.dispatcher.executorService.shutdown()
}
However I have to add subprotocol - "websocket" . How can I achieve that ? Is it possible ?
I haven't confirmed but it should be possible with
request = Request.Builder()
.url(...)
.addHeader("Sec-WebSocket-Protocol", "graphql-ws")
...
.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 add Basic Authentication Header

I want to add Basic Authentication header to my request done with OkHttp3.
Here is my code:
// Adding Authentication Header
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic(username, password);
return response.request().newBuilder().header("Authorization", credential).build();
}
});
//
client.connectTimeout(10, TimeUnit.SECONDS);
client.writeTimeout(10, TimeUnit.SECONDS);
client.readTimeout(10, TimeUnit.MINUTES);
RequestBody body = RequestBody.create(null, new byte[]{});
if( json != null) {
body = RequestBody.create(MediaType.parse(
"application/json"),
json.toString()
);
}
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
client.build().newCall(request).enqueue(callback);
Unfortunately no Authentication header is added and I really can't find the mistake.
Authenticator is primarily intended for "reactive" authentication, i.e. it is not called automatically and every time. The main scenario for its automatic invocation is a 401 "Unauthorized" server response.
You should probably use a regular Interceptor instead for your case, just register it using your client builder like this:
client.addInterceptor(
object : Interceptor { chain ->
val request = chain.request().newBuilder()
.addHeader(...)
.build()
return chain.proceed(request)
}
)
In order to do that, you need to use Interceptors offered by OkHttp Builder. Interceptors, as the name suggests, can intercept and requests sent through the client or any response received by the client before it passes them to your application.
In your case, you need to add this custom interceptor by intercepting the request, and attaching a new header to it before it leaves your client.
Adding a custom header to every request
return OkHttpClient.Builder()
.addInterceptor { chain ->
var request = chain.request()
var url = request.url()
request = request.newBuilder()
.removeHeader("needAuthToken")
.addHeader("Content-Type", "application/json")
// Feel free to add any other headers
.url(url)
.build()
chain.proceed(request)
}
Feel free to wrap this in any control flow conditions in case attachment of these headers matter on a predicate.

Retrofit2 send Bearer Token

I've tried sending the token with a HeaderMap but get a 401 code response. The way my project is setup is that I have a separate file for my ApiClient and I have a OkHttpClient Interceptor and a HttpLoggingInterceptor to see whats going on, however I can't get the Bearer Token to work. I've seen solutions that add it to the interceptor as a header in the interceptor and I've tried this but since my token is saved in SharedPreferences I can't get it to work in the ApiClient class I have.
This is the ApiClient
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Gson gson = new GsonBuilder().serializeNulls().setLenient().create();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#NotNull
#Override
public okhttp3.Response intercept(#NotNull Chain chain) throws IOException {
Request originalRequest = chain.request();
Request newRequest = originalRequest.newBuilder()
//I would add the header here
//I tried this but it says on "ApiClient.this" cannot be referenced from static context
// .header("Authorization" , SharedPreferencesHelper.getUserToken(ApiClient.this));
.build();
return chain.proceed(newRequest);
}
})
.addInterceptor(interceptor)
.build();
retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.0.6:8000/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
This is the method from SharedPreferencesHelper.getUserToken(MainActivity.this)
public static String getUserToken(Context context) {
SharedPreferences sp = getSharedPreferences(context);
return sp.getString(USER_TOKEN, null);
}
This is the current call where the response is 401, If I don't add the Accept => application/json the response url is incorrect and also returns a html page when I need a simple response return response("LoggedOut", 200); //this is the response in the api
Map<String, String> headers = new HashMap<>();
headers.put("Accept", "application/json");
headers.put("Token", SharedPreferencesHelper.getUserToken(MainActivity.this));
Call<Void> call = apiInterface.LogoutUser(headers);
call.enqueue(new Callback<Void>() {
// onResponse and onFailure here
}
For example without the Accept header this is the response in the Logcat
D/OkHttp: --> GET http://192.168.0.6:8000/api/logout
D/OkHttp: Token: wE1Y8IxJpwyXtvw0fYoXZAlQ6qCx24YtzonQIeJBQSHmNppe0Sn1kLYDgZKCw4MKbpab4Vspf61Nzer1
D/OkHttp: --> END GET
D/OkHttp: <-- 200 OK http://192.168.0.6:8000/login
//a bunch of html that's the web page at this route, notice the /api is missing
How can I send this correctly?
EDIT:
I"m using a Laravel project for the backend and this is the relevant route
Route::middleware('auth:sanctum')
->get('/logoutApi', function (Request $request) {
$request->user()->tokens()->delete();
return response("LoggedOut", 202);
});
create class Authenticator, like:
const val HEADER_TOKEN_FIELD = "Authorization"
class ClassAuthenticator(
private val pref: SharedPref
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
return response.request().newBuilder()
.header(HEADER_TOKEN_FIELD, pref.getToken())
.build()
}
}
then add interceptor in your client with:
val httpClient = OkHttpClient.Builder()
.authenticator(ClassAuthenticator(pref))
.addInterceptor { chain ->
val request = chain.request()
val httpRequest = request.newBuilder()
.addHeader(HEADER_TOKEN_FIELD,
"Bearer ${pref.getToken()}")
.build()
val response = chain.proceed(httpRequest)
response
}
.build()

Categories

Resources