I'm using retrofit 1.9.0 and I had tried the following code to get a response in json format:
public void Execute(String email, String password, Callback<User> callback) {
final Callback<User> cb = callback;
RestAdapter restAdapter = buildRestAdapter();
System.out.println("Email " + email + " passowrd " + password);
User user = new User();
user.setEmail(email);
user.setPassword(password);
restAdapter.create(YutonAPI.class).postLogin(
user,
new Callback<User>() {
#Override
public void success(User user, Response response) {
System.out.println("succes");
System.out.println(response.getBody());
}
#Override
public void failure(RetrofitError error) {
System.out.println("error "+ error);
}
});
}
So this line of code:
System.out.println(response.getBody());
Should give me a response in json format however it didn't work because I'm getting the following output:
Link: http://i.imgur.com/mBQs1LL.png
So this is how my response in json format should look like:
{
"user": {
"image": "https://www.gravatar.com/avatar/e0a190604dc3dd2ee7b66bb95c20ef7f?d=identicon&s=512"
"email": "a#hotmail.com"
"name": "a"
"id": "566dfac21043a31820bf1ae6"
} -
}
I had already tested it on my server where I was making a post request. Below you can see a screenshot of it:
Link: http://i.imgur.com/PtEMR12.png
The issue here is that response.getBody() returns a TypedInputStream object, which you can't directly output because it isn't a String.
To read a TypedInputStream there are several options, as posted in: Retrofit callback get response body, the easiest being:
String body = new String(((TypedByteArray) response.getBody()).getBytes());
If the following error is thrown:
java.lang.ClassCastException: retrofit.client.UrlConnectionClient$TypedInputStream cannot be cast to retrofit.mime.TypedByteArray
Then make sure that you set .setLogLevel(RestAdapter.LogLevel.FULL) on the RestAdapter that you use to create the service.
Related
Using Retrofit I post my contact list on the phone without authentication. I need to do retrofit basic authentication, but as far as I can't see from the internet. Can you help me, please?
This is my Code:
public void GetContactsIntoArrayList(){
mAPIService = ApiUtils.getAPIService();
final User user = new User();
final Post post = new Post();
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null, null, null);
while (cursor.moveToNext()) {
int i = 0;
name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phonenumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
StoreContacts.add(name + " " + ":" + " " + phonenumber);
user.setphoneNumber(phonenumber.toString().trim());
user.setname(name.toString().trim());
List<User> phoneList = new ArrayList<>();
phoneList.add(user);
post.setUsers(phoneList);
sendPost(post);
}
cursor.close();
}
public void sendPost(Post post){
mAPIService.savePost(post).enqueue(new Callback<Post>() {
#Override
public void onResponse(Call<Post> call, Response<Post> response) {
Log.d("requestError", "onResponse: "+ call.request().body().toString());
if(response.isSuccessful()) {
Log.i("Is Ok?","OK :)");
}
}
#Override
public void onFailure(Call<Post> call, Throwable t) {
}
});
}
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class)
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
My code is in Kotlin, just in case you were looking for Java. But can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/
You can add auth value in header of the request like if you want to send auth token then follow below step:
#POST("/auth/update-contactno")
#Headers(
"Content-Type: application/json",
Constants.headerApp,
Constants.headerLanguage,
Constants.headerPlatform,
Constants.headerVersion
)
fun updateMobileNumber(#Header(Constants.authorization) token: String?, #Body verifyForgotPasswordOTPInput: VerifyForgotPasswordOTPInput): Call<JsonObjectResponse<UserModel>>
And call updateMobileNumber() like :
apiService.updateMobileNumber(token, verifyForgotPasswordOTPInput)
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/")
When I fail to parse the json from the server, I try to collect the situation.
I can see what the server gave me using the class that implements the Interceptor.(LoggingInterceptor)
However, I do not seem to be able to get the value in 'onFailure()', a situation where I need to collect errors. Because it only provides 'Call' and 'Throwable'. How do I get raw data from the server in 'onFailure()'?
Below is my code.
LoggingInterceptor
public class LoggingInterceptor implements Interceptor {
//로그에 쓰일 tag
private static final String TAG = CalyApplication.class.getSimpleName() + "/" + LoggingInterceptor.class.getSimpleName();
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
String responseString = new String(response.body().bytes());
//yes, I can see response in here. but I need it in 'onFailure()'.
Logger.i(TAG, "code : " + response.code() + "\n" + responseString);
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), responseString))
.build();
}
}
Actrivity
void fetchData(){
ApiClient.getService().test(
"test"
).enqueue(new Callback<BasicResponse>() {
#Override
public void onResponse(Call<BasicResponse> call, Response<BasicResponse> response) {
BasicResponse body = response.body();
switch (response.code()){
case 200:
break;
default:
break;
}
}
#Override
public void onFailure(Call<BasicResponse> call, Throwable t) {
//I want get Response object in here!
//but it only provides Call&Throwable
}
});
}
Thanks!
If you get a 4xx or 5xx (error)status code then the onResponse is called, not the onFailure. You get a response body(2xx) or error body accordingly only if the call was successful. So in onResponse you should have the following structure:
if (response.isSuccessful()) {
// Get response body
} else if (response.errorBody() != null) {
// Get response errorBody
String errorBody = response.errorBody().string();
}
Edit: More info about how to retrieve the errorBody can be found here.
I'm having problems implementing a custom class as response JSON in Retrofit2.
The call succeeds and when I log the body (using HttpLoggingInterceptor) I can see the JSON is fetched correctly.
The only problem is that it is not parsed into the custom class I created.
Here is my ServiceGenerator:
public class ServiceGenerator
{
//Base url for the API
public static final String API_BASE_URL = "http://base.url";
private static Retrofit.Builder GSONBuilder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <T> T createJSONService(Class<T> serviceClass)
{
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
Retrofit retrofit = GSONBuilder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
Here is the ServiceInterface:
public interface ServiceInterface
{
class UserResponse
{
public int id;
public String email;
public String created_at;
#Override
public String toString()
{
return "UserResponse{" +
"id: " + id +
", email: " + email +
", created_at: " + created_at +
"}";
}
}
#GET("user/{userId}")
Call<UserResponse> currentUser(#Path("userId") int userId);
}
And this is where I actually call it:
public void getUser(int userId)
{
ServiceInterface clientCreate = ServiceGenerator.createJSONService(ServiceInterface.class);
Call<ServiceInterface.UserResponse> callCreate = clientCreate.currentUser(userId);
callCreate.enqueue(new Callback<ServiceInterface.UserResponse>()
{
#Override
public void onResponse(Call<ServiceInterface.UserResponse> call, Response<ServiceInterface.UserResponse> response)
{
ServiceInterface.UserResponse user = response.body();
if (user == null)
{
System.out.println("error");
}
else
{
System.out.println(user.toString());
//This line gets printed, but the class is empty
//What it should show: UserResponse{id: 5, email: "test#email.com", created_at: "2016-03-02"}
//What it actually shows: UserResponse{id: 0, email: null, created_at: null}
}
}
#Override
public void onFailure(Call<ServiceInterface.UserResponse> call, Throwable t)
{
System.out.println("Fail: " + t.getMessage());
}
});
}
I feel like I did everything right, is there any explanation why the GsonConverter does not convert the response to my custom class (UserResponse)?
To make myself even more clear, here is the actual JSON response (using Postman):
{"id": 5, "email": "test#email.com", "created_at": "2016-03-02"}
Thanks in advance!
Edit 1:
For anyone interested.
I have just figured out that if I use a String as a return type it actually writes all the data to the String.
So that means the fault lies with the conversion. I think that somewhere along the way I made a mistake with the GSONBuilder.
I have 500 internal server error, every time when i try to send POST request via Retrofit. When i sending GET request, it sending correctly. I'm sure that with serverside everyting is ok. What's wrong with my code ?
String ENDPOINT = "http://52.88.40.210";
//model for request
FriendModel ff = new FriendModel();
ff.setFriendNumber("380935275259");
ff.setId(516);
ff.setNumber("380936831127");
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ENDPOINT)
.build();
WayfAPI api = adapter.create(WayfAPI.class);
api.getFriendsLocation(ff, new Callback<List<FriendLocationModel>>() {
#Override
public void success(List<FriendLocationModel> friendLocationModels, Response response) {
for (FriendLocationModel ff : friendLocationModels) {
Log.d("myLogs", "===========Successful==========");
Log.d("myLogs", "Id: " + ff.getId());
Log.d("myLogs", "Number: " + ff.getNumber());
Log.d("myLogs", "GeoLocation: : " + ff.getGeoLocation());
}
}
#Override
public void failure(RetrofitError error) {
Log.d("myLogs", "-------ERROR-------");
Log.d("myLogs", Log.getStackTraceString(error));
}
});
}
Declaration of request:
#Headers({
"Accept: application/json",
"Content-type: application/json"
})
#POST("/api/geo/getLoc")
public void getFriendsLocation(#Body FriendModel friendModel, Callback<List<FriendLocationModel>> response);
Exampe of request and response from Postman:
It seems that in postman you're sending an array of FriendModel, but in your code you're sending a single object.
Just change the object you're sending, and instead of sending a single object, send a List as the server expects
List<FriendModel> friendsList = new ArrayList<FriendModel>();
FriendModel ff = new FriendModel();
ff.setFriendNumber("380935275259");
ff.setId(516);
ff.setNumber("380936831127");
friendsList.add(ff);
You should also change this signature:
public void getFriendsLocation(#Body FriendModel friendModel, Callback<List<FriendLocationModel>> response);
to
public void getFriendsLocation(#Body List<FriendModel> friendModel, Callback<List<FriendLocationModel>> response);