I have created the next savePartner() method inside PartnerController class like this:
public void savePartner(View partnerForm) {
context = partnerForm.getContext();
PartnerDto partner = createPartner(partnerForm);
String jsonPartner = convert(partner);
Call<String> call = appAPI.savePartner("application/json", jsonPartner);
Log.i(TAG, "getPartners submitted to API.");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
String responseCall = response.body();
} else {
System.out.println(response.errorBody());
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
TableRow rowHeader = new TableRow(context);
TextView name = new TextView(context);
name.setText(t.getMessage());
rowHeader.addView(name);
//partnerForm.addView(rowHeader);
t.printStackTrace();
}
});
}
And I have added the method savePartner to retrofit interface:
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface IApplicationApi {
#GET("Partner/")
//Call<List<PartnerDto>> loadPartners(#Header("Authorization") String authorization);
Call<List<PartnerDto>> loadPartners();
#POST("Partner/")
Call<String> savePartner(#Header("Content-Type") String content_type, #Body String partner);
}
When I execute the post call in postman works (code 200), but I debugged the previous in android-studio and I obtain the next error:
Response{protocol=http/1.1, code=400, message=Bad Request, url=https://localhost/Partner/}
And I can't obtain more info about the error. The request is the next:
Request{method=POST, url=https://localhost/Partner/, tags={class retrofit2.Invocation=administracion.MyProject.APIService.IApplicationApi.savePartner() [application/json, {"email":null,"id":4,"lastname":null,"name":"me","phonenumber":0,"productamount":0.0,"productquantity":0.0,"registereddate":"2021-02-10T00:00:00"}]}}
I put these values on postman, and it works like a charm. I don't know why this request is bad. Could someone give me some clue?
Thanks in advance for the help! ^^
Updated 01/03/2021
I can get the cause of the error using httplogginginterceptor, I share this in case someone more need it :)
https://howtodoinjava.com/retrofit2/logging-with-retrofit2/
you can use HttpLoggingInterceptor and log your request. I hope you are missing a field in your json body or request body
try replacing this #POST("Partner/")
with #POST("Partner")
Related
I am using retrofit library with post request, but i did not found data. Give "Internal server error" message.
API_1 : http://www.fabgrad.com/dummy_api_1/
type : POST
data : { us_id:23 }
interface -
public interface FirstApi {
public static String URl = "http://www.fabgrad.com/";
#FormUrlEncoded
#POST("dummy_api_1")
Call<Titles> getData(#Field("us_id") String id);
}
Using retrofi in main activity -
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(FirstApi.URl)
.addConverterFactory(GsonConverterFactory.create())
.build();
FirstApi categoryMenuApi = retrofit.create(FirstApi.class);
String s="23";
Call<Titles> categoryMenuCall = categoryMenuApi.getData(s);
categoryMenuCall.enqueue(new Callback<Titles>() {
#Override
public void onResponse(Call<Titles> call, Response<Titles> response) {
Titles list = response.body();
}
#Override
public void onFailure(Call<Titles> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
I am new in retrofit So please help
You only have to add / at the end of your endpoint #POST("dummy_api_1")
Just like:
#POST("dummy_api_1/")
Utils.java
/**
* Created by faiz on 15/08/17.
*/
package com.example.android.whereabouts;
import android.util.Log;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class Utils {
private String apiresponse;
private OkHttpClient okHttpClient;
public Utils(String url){
okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("exception",e.toString());
}
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
apiresponse = response.body().string();
Log.e("onResponse",apiresponse);
}
});
}
public String getData(){
if(apiresponse != null)
return apiresponse ;
else
return "error";
}
}
When i instantiate this class in my main activity and try to Log return value of getData method, it logs "error" instead of the value of variable apiresponse .
Its obvious that that it takes some time to get response from the server and getData call gets executed before the server returns a response.
So how to make sure getData gets called after onResponse has been executed.
Instead of getting a callback in Utility, You can implement that in your Activity so that call back will come to ur activity and you can update in UI without any issue.
public Utils(String url, Callback callback){
okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(callback);
}
in your actvity, you can call like,
public void getdata() {
new Utils("[url]", new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("exception",e.toString());
}
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
apiresponse = response.body().string();
Log.e("onResponse",apiresponse);
// here you can show in UI.
}
})
}
or you can create a separate custom interface and you can do same after getting the response from the server.
You can implement a callback mechanism and call the callback method from inside the onResponse(Call call, okhttp3.Response response) method.
Here is an example. You should define this in the Utils class -
public interface Callback {
void getData(String data);
}
private Callback callback;
In the constructor pass in the activity reference when you instantiate the Utils class.
// In the activity
utilsInstance = new Utils(url, this);
// In your Utils class
public Utils(String url, Callback activityCallback) {
callback = activityCallback
}
In your activity, you need to implement this interface -
public class RetrofitActivity implements Utils.Callback {
#Override
public void getData(String data) {
// do stuff
}
}
And in your OnResponse() method, you'll call this method like so -
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
apiresponse = response.body().string();
callback.getData(apiresponse);
Log.e("onResponse",apiresponse);
}
I found two workarounds which I'll share here and I request the people who answered this question to share their thoughts on this.(I appreciate the answers shared on this question..thanks to you all )
Note: Its more of a "clean code question" than "how to get this thing to work question"
Solution 1:
We can wait till the onResponse method gets called in getData() like this
while(true)
if(apiresponse!=null)
return(apiresponse);
to make sure this is not an indefinite while loop we set the variable apiresponse to something in both onResponse and OnFailure methods(either one will surely get executed) to break the loop.
this one seems to work but its pretty naive to me to use infinite loop and break it.
Solution 2:
Writing an AsyncTask and the Executing Utils class in the doInBackground method of that async task.
(I think the second approach makes sense as it falls under standard practices of android so it makes the thing work and also satisfies the best practices).
Another thing: an obvious question to some would be that when you're ready to write the whole async task inside the activity, then why is it an issue to write the Utils.java code directly inside the activity. My response to that is , despite of writing the asynctask in the activity, its better because it saves me from manually handling Handlers to create another thread inside onResponse to update the UI and it also falls under standard practices . So I think this approach makes more sense overall.
Step 1 : In Utils method pass calling activity as below
public Utils(CallingActivity activity , String url)
{
Request request = new Request.Builder().url(url).build();
okHttpClient.newCall(request).enqueue(activity);
}
Step 2 : Implement Callback of OkHttpClient in your calling activity.
Step 3 : Override onFailure() and onResponse() of OkHttpClient and call Utils(this,url) in calling activity.
I have developed a web service using Java and Jersey. Now I am trying to connect into it, call its methods and get data, using android.
Below is the related part of the web service.
import bean.PatientBean;
import bean.UserBean;
import db.PatientImpl;
import db.PatientInterface;
import db.UserImpl;
import db.UserInterface;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/patient")
public class PatientJSONService
{
#POST
#Path("/getPatientById/{Id}")
#Produces(MediaType.APPLICATION_JSON)
public PatientBean getPatientById(#PathParam("Id")String Id)
{
PatientInterface patinetInterface=new PatientImpl();
PatientBean patientById = patinetInterface.getPatientById(Id);
return patientById;
}
}
In my android application, I am using Retrofit 2 to call the above REST method.
private void restCall()
{
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
YourEndpoints request = retrofit.create(YourEndpoints.class);
Call<PatientBean> yourResult = request.getPatientById("ERTA001");
yourResult.enqueue(new Callback<PatientBean>() {
#Override
public void onResponse(Call<PatientBean> call, Response<PatientBean> response) {
try {
// Log.d("MainActivity", "RESPONSE_A: " + response.body().toString());
Log.d("MainActivity", "RESPONSE: " + response.errorBody().string());
}
catch(Exception e)
{
e.printStackTrace();
}
}
#Override
public void onFailure(Call<PatientBean> call, Throwable t) {
try {
t.printStackTrace();
Log.d("MainActivity", "RESPONSE: "+"FAILED");
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
}
Below is my EndPoint interface
public interface YourEndpoints {
#POST("patient/getPatientById/{Id}")
Call<PatientBean>getPatientById(#Body String Id);
}
However When I run the code, I get a HTML response from Apache Tomcat Server, which basically says HTTP Status 405 - Method Not Allowed.
How can I solve this issue?
Change your ws endpoint to #GET, and then change your rest client to below code:
#GET("patient/getPatientById/{Id}")
Call<PatientBean>getPatientById(#Path("Id") String Id);
GET should be used to retrieve data from the server.
POST should be used to send data to the server.
If you are using GSON along with RetroFit, you should not need your own implementation within getPatientById(). And, yes you should be using a GET method.
public interface PatientService {
#GET("patient/getPatientById/{Id}")
Call<PatientBean> getPatientById(#Path("Id") String id);
}
If your PatientBean is setup correctly, you should be able to call the following to get a fully formed instance of the class:
PatientService service = retrofit.create(PatientService.class);
Call<PatientBean> call = service.getPatientById("ERTA001");
call.enqueue(new Callback<PatientBean> {
#Override
public void onResponse(Call<PatientBean> call, Response<PatientBean> response) {
mPatientBean = response.body();
}
#Override
public void onFailure(Call<PatientBean> call, Throwable throwable) {
throwable.printStackTrace();
}
});
I'm trying to set the User-Agent with React Native on Android. Did some research and it looks like I should use an okhttp Interceptor. An example that I've found explains how this should be done(Link) but then I am not sure on how to register the Interceptor.
So in order to set the User-Agent I am using this class:
public class CustomInterceptor implements Interceptor {
#Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader("User-Agent")
.header("User-Agent", "Trevor")
.build();
return chain.proceed(requestWithUserAgent);
}
}
Then what's left is to register the above interceptor so where it should be done? Maybe in MainActivity.java?
OkHttpClient okHttp = new OkHttpClient();
okHttp.interceptors().add(new CustomInterceptor());
I am not getting any errors when building the app so I think that the CustomInterceptor should be fine - just need to make the app use it.
UPDATE:
I'm currently trying to register the interceptor in MainActivity but it won't pick it up:
public class MainActivity extends ReactActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OkHttpClient client = new OkHttpClient();
client.networkInterceptors().add(new CustomInterceptor());
};
};
None of the answers here worked for me for RN 0.63.2. I was able to get it working and in my research was able to find the (albeit very scarce) documentation for the support of this feature.
The only documentation I could find for this was this PR where someone added support for this feature (and broke the currently accepted answer). When I tried adding the interceptor as documented in the PR I got an exception related to CookieJar which I was able to find a solution to in this (unresolved 🙄) issue.
TLDR:
Add a Java class in the same folder as your MainApplication called UserAgentInterceptor.java and place this in it:
package YOUR.PACKAGE.NAME; // <-- REPLACE ME
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class UserAgentInterceptor implements Interceptor {
public UserAgentInterceptor() {}
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", "YOUR USER AGENT") // <-- REPLACE ME
.build();
return chain.proceed(requestWithUserAgent);
}
}
Then create another Java class in the same folder named UserAgentClientFactory.java and place this in it:
package YOUR.PACKAGE.NAME; // <-- REPLACE ME
import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.ReactCookieJarContainer;
import okhttp3.OkHttpClient;
public class UserAgentClientFactory implements OkHttpClientFactory {
public OkHttpClient createNewNetworkModuleClient() {
return new OkHttpClient.Builder()
.cookieJar(new ReactCookieJarContainer())
.addInterceptor(new UserAgentInterceptor())
.build();
}
}
Then in your MainApplication onCreate method register the factory like this:
...
import com.facebook.react.modules.network.OkHttpClientProvider;
...
#Override
public void onCreate() {
super.onCreate();
OkHttpClientProvider.setOkHttpClientFactory(new UserAgentClientFactory());
// Your other code stuffs
}
And that's it!
So I've finally figured it out. Here is the solution for overriding the User-Agent of okhttp3 with React Native.
Create a file called CustomInterceptor.java:
package com.trevor;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
public class CustomInterceptor implements Interceptor {
public CustomInterceptor() {}
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", "Trevor")
.build();
return chain.proceed(requestWithUserAgent);
}
}
Then in MainActivity.java override the onCreate method:
...
import com.facebook.react.modules.network.OkHttpClientProvider;
...
public class MainActivity extends ReactActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
attachInterceptor();
}
private void attachInterceptor() {
OkHttpClient client = OkHttpClientProvider.getOkHttpClient();
client.networkInterceptors().add(new CustomInterceptor());
}
}
Note that I'm importing com.facebook.react.modules.network.OkHttpClientProvider; and overriding that client instead of creating a vanilla OkHttpClient since this is the one that React Native will use.
React Native is iterating so quickly that the accepted answer didn't work for me.
For RN 0.27.2 I had to import okhttp3.OkHttpClient in my CustomInterceptor and change the attachInterceptor() method in MainActivity to replace the client.
private void attachInterceptor() {
OkHttpClient currentClient = OkHttpClientProvider.getOkHttpClient();
OkHttpClient replacementClient = currentClient.newBuilder().addNetworkInterceptor(new CustomInterceptor()).build();
OkHttpClientProvider.replaceOkHttpClient(replacementClient);
}
Everything else from ekonstantinidis's answer works for me.
Old issue, but we still ran into the same problem with React Native 0.59. This is what we did to fix (in Kotlin), as recent versions of okhttp prevent (and throw an exception) when trying to add an interceptor to an already initialized client:
import android.os.Build
import com.facebook.react.modules.network.OkHttpClientFactory
import com.jaredrummler.android.device.DeviceName
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
class UserAgentInterceptor(val userAgent: String): Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val correctRequest = originalRequest.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", userAgent)
.build()
return chain.proceed(correctRequest)
}
}
class UserAgentClientFactory(val appName: String, val appVersion: String, val buildNumber: String): OkHttpClientFactory {
private fun userAgentValue(): String {
val deviceName = DeviceName.getDeviceName()
val osVersion = Build.VERSION.RELEASE
return "$appName/$appVersion (build: $buildNumber; device: $deviceName; OS: Android $osVersion)"
}
override fun createNewNetworkModuleClient(): OkHttpClient {
val builder = com.facebook.react.modules.network.OkHttpClientProvider.createClientBuilder()
return builder.addInterceptor(UserAgentInterceptor(userAgent = userAgentValue())).build()
}
}
This was done in a shared library between 2 apps, thus why we passed in the app name, version, and build number.
Usage from the app itself looked like:
private fun configureUserAgent() {
val versionName = BuildConfig.VERSION_NAME
val versionCode = BuildConfig.VERSION_CODE
OkHttpClientProvider.setOkHttpClientFactory(UserAgentClientFactory(appName = "My App", appVersion = versionName, buildNumber = "$versionCode"))
}
This was called from the onCreate method in the main activity of the app.
Hope this helps!
I've implemented this functionality using OkHttp and my code is pretty the same as yours - and everything works fine.
Consider using addHeader("User-Agent", "Trevor") instead of header("User-Agent", "Trevor"), because the latter will replace all of already set headers.
I'm using okHttp.networkInterceptors().add(new CustomInterceptor()); instead of okHttp.interceptors().add(new CustomInterceptor());, but I don't think it's a matter of concern here.
Update I do it in onCreate() method too. Everything works as it should.
I'm trying to make Cross Site Request using GWT Request builder, which i couldn't get it to work yet. As you can see, this is much of a Sample GWT Project and i have gone through https://developers.google.com/web-toolkit/doc/latest/tutorial/Xsite . But still i'm missing something.
I'm Posting the code here. What am i missing ..?
package com.gwt.reqbuilder.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
public class GWTRequestBuilder implements EntryPoint
{
private static final String JSON_URL = "http://localhost:8000/?q=ABC&callback=callback125";
public void onModuleLoad()
{
GWTPOSTHTTP();
}
public void GWTPOSTHTTP()
{
String postUrl="http://localhost:8000";
String requestData="q=ABC&callback=callback125";
RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, postUrl);
try {
builder.sendRequest(requestData.toString(), new RequestCallback()
{
public void onError(Request request, Throwable e)
{
Window.alert(e.getMessage());
}
public void onResponseReceived(Request request, Response response)
{
if (200 == response.getStatusCode())
{
Window.alert(response.getText());
} else {
Window.alert("Received HTTP status code other than 200 : "+ response.getStatusText());
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
Window.alert(e.getMessage());
}
}
}
Actually we can make Cross Site Requests from GWT RequestBuilder if we can set in Servlet Response Header
Response.setHeader("Access-Control-Allow-Origin","http://myhttpserver");
It's working Cool , if anyone need the GWT Project and Python Servlet, please do let me know, i can upload the files.
GWT Client Code : https://github.com/manikandaraj/MLabs/tree/master/GWT/GWTClient
You've missed to finish reading the tutorial.
Direct quote from the tutorial :
The RequestBuilder code is replaced by a call to the getJson method. So you no longer need the following code in the refreshWatchList method:
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
displayError("Couldn't retrieve JSON");
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
updateTable(asArrayOfStockData(response.getText()));
} else {
displayError("Couldn't retrieve JSON (" + response.getStatusText()
+ ")");
}
}
});
} catch (RequestException e) {
displayError("Couldn't retrieve JSON");
}
Which is broadly what you've got, and should be replaced by a JSNI function given in the tutorial a few lines below :
/**
* Make call to remote server.
*/
public native static void getJson(int requestId, String url,
StockWatcher handler) /*-{
var callback = "callback" + requestId;
// [1] Create a script element.
var script = document.createElement("script");
script.setAttribute("src", url+callback);
script.setAttribute("type", "text/javascript");
// [2] Define the callback function on the window object.
window[callback] = function(jsonObj) {
// [3]
handler.#com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
window[callback + "done"] = true;
}
...