Retrofit POST method returns error 400 - android

I would like to call a POST Method(Django REST framework) in Retrofit with a For that, I call as follow from the postman and works fine for me.
I have done the Android part as follows:
API INTERFACES:
public interface SOService {
#FormUrlEncoded
#POST("/api-auth/")
Call<Tokken> get_tokken(#Field("username") String username, #Field("password") String password);
}
APIUtility class as
public class ApiUtils {
public static final String BASE_URL = "http://10.0.2.2:8000/";
public static SOService getSOService() {
return RetrofitClient.getClient(BASE_URL).create(SOService.class);
}
}
RetrofitClient as :
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
And finally, call the function as following
private void signIn() {
boolean isValid = validate();
if (isValid) {
mService.get_tokken(user.getText().toString(), password.getText().toString()).enqueue(new Callback<Tokken>() {
#Override
public void onResponse(Call<Tokken> call, Response<Tokken> response) {
if (response.isSuccessful()) {
System.out.println("Te lo imprimo");
System.out.println(response.body().toString());
Toast.makeText(LoginActivity.this, "tokken recibido", Toast.LENGTH_SHORT).show();
} else {
int statusCode = response.code();
// handle request errors depending on status code
}
}
#Override
public void onFailure(Call<Tokken> call, Throwable t) {
Toast.makeText(LoginActivity.this, "Error al recibir tokken", Toast.LENGTH_SHORT).show();
t.printStackTrace();
Log.d("MainActivity", "error loading from API");
}
});
/*startActivity(new Intent(this, RolSelection.class));*/
}
}
And the final result is always the same, I get this message in the server:
[17/Apr/2018 01:12:33] "POST /api-auth/ HTTP/1.1" 200 52
But in Android I get this:
I/System.out: Te lo imprimo
Tokken{tokken='null'}
Any idea why the tokken is null? When I use postman I get a result.
UPDATE with the Tokken class:
public class Tokken {
#SerializedName("tokken")
#Expose
private String tokken;
public String getTokken() {
return tokken;
}
public void setTokken(String tokken) {
this.tokken = tokken;
}
#Override
public String toString() {
return "Tokken{" +
"tokken='" + tokken + '\'' +
'}';
}
}

UPDATE: change field name in Tokken class from #SerializedName("tokken") into #SerializedName("token") as on attached screenshot from Postman in response you get "token" key but not "tokken".
Maybe it's not the root cause but one of the problem for sure:
you didn't configure your retrofit client properly, you missed to add http client:
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();

I think your problem is that your bean object (Token) has a GSON annotation to serialize as tokken.
if you change your #SerializedName("tokken”) to #SerializedName("token”), and assuming the request has no other problems, that should correctly deserialize.
I don’t know why you call it tokken in one side and token in another, but I would avoid it if possible, unless you’re planning on adding unit test to ensure future you doesn’t forget about this.
Another way to pass a Body (which may be easier, depending…) is to use a HashMap:
#POST("/api-auth/“)
Call<Tokken> get_tokken(#Body HashMap<String, Object> body);
Then you can pass a map containing:
[“username”, “YourUsername”],
[“password”, “YourPassword”]
But without extra logging (or a proxy in-between to see what is actually going on), it’s very hard to debug.
Remember that your question’s title is "Retrofit POST method returns error 400”. But your token being null is a side-effect of your API returning 400 error. 400 Error is “BAD REQUEST”, so something is not what your server expects.
nitpick: I’d rename your API method to getToken(…) or fetchToken(…) to be more Java/Kotlin/Android friendly and also more self-explanatory.

Two changes
change tokken to token
#SerializedName("tokken")
#Expose
private String tokken;
to
#SerializedName("token")
#Expose
private String tokken;
remove the extra "\" in SOService, it should be
#FormUrlEncoded
#POST("api-auth/")

Related

Square retrofit server mock for testing

What's the best way to mock a server for testing when using the square retrofit framework.
Potential ways:
Create a new retrofit client and set it in the RestAdapter.Builder().setClient(). This involves parsing the Request object and returning the json as a Response object.
Implement this annotated interface as a mock class and use that in place of the version provided by RestAdapter.create() (wont test gson serialisation)
?
Ideally I want to have the mocked server provide json responses so I can test the gson serialisation at the same time.
Any examples would be greatly appreciated.
Mock Retrofit 2.0 Requests for Testing
As the old mechanisms like creating MockClient class and implementing it from Client are not working anymore with Retrofit 2.0, here I describe a new way of doing that. All what you need to do now is to add your custom interceptors for OkHttpClient like it is shown below. FakeInterceptor class just overrides intercept method and in the case if application is in DEBUG mode return given JSON.
RestClient.java
public final class RestClient {
private static IRestService mRestService = null;
public static IRestService getClient() {
if(mRestService == null) {
final OkHttpClient client = new OkHttpClient();
// ***YOUR CUSTOM INTERCEPTOR GOES HERE***
client.interceptors().add(new FakeInterceptor());
final Retrofit retrofit = new Retrofit.Builder()
// Using custom Jackson Converter to parse JSON
// Add dependencies:
// com.squareup.retrofit:converter-jackson:2.0.0-beta2
.addConverterFactory(JacksonConverterFactory.create())
// Endpoint
.baseUrl(IRestService.ENDPOINT)
.client(client)
.build();
mRestService = retrofit.create(IRestService.class);
}
return mRestService;
}
}
IRestService.java
public interface IRestService {
String ENDPOINT = "http://www.vavian.com/";
#GET("/")
Call<Teacher> getTeacherById(#Query("id") final String id);
}
FakeInterceptor.java
public class FakeInterceptor implements Interceptor {
// FAKE RESPONSES.
private final static String TEACHER_ID_1 = "{\"id\":1,\"age\":28,\"name\":\"Victor Apoyan\"}";
private final static String TEACHER_ID_2 = "{\"id\":1,\"age\":16,\"name\":\"Tovmas Apoyan\"}";
#Override
public Response intercept(Chain chain) throws IOException {
Response response = null;
if(BuildConfig.DEBUG) {
String responseString;
// Get Request URI.
final URI uri = chain.request().url().uri();
// Get Query String.
final String query = uri.getQuery();
// Parse the Query String.
final String[] parsedQuery = query.split("=");
if(parsedQuery[0].equalsIgnoreCase("id") && parsedQuery[1].equalsIgnoreCase("1")) {
responseString = TEACHER_ID_1;
}
else if(parsedQuery[0].equalsIgnoreCase("id") && parsedQuery[1].equalsIgnoreCase("2")){
responseString = TEACHER_ID_2;
}
else {
responseString = "";
}
response = new Response.Builder()
.code(200)
.message(responseString)
.request(chain.request())
.protocol(Protocol.HTTP_1_0)
.body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))
.addHeader("content-type", "application/json")
.build();
}
else {
response = chain.proceed(chain.request());
}
return response;
}
}
Source code of project on GitHub
I decided to try method 1 as follows
public class MockClient implements Client {
#Override
public Response execute(Request request) throws IOException {
Uri uri = Uri.parse(request.getUrl());
Log.d("MOCK SERVER", "fetching uri: " + uri.toString());
String responseString = "";
if(uri.getPath().equals("/path/of/interest")) {
responseString = "JSON STRING HERE";
} else {
responseString = "OTHER JSON RESPONSE STRING";
}
return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes()));
}
}
And using it by:
RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setClient(new MockClient());
It works well and allows you to test your json strings without having to contact the real server!
Testing JSON deserialization to your objects (presumably with TypeAdapters?) seems like a separate problem that require separate unit tests.
I use version 2 personally. It affords type-safe, refactor-friendly code that can be easily debugged and altered. After all, what good is declaring your API as interfaces if you aren't creating alternate versions of them for testing! Polymorphism for the win.
Another option is using a Java Proxy. This is actually how Retrofit (currently) implements its underlying HTTP interaction. This will admittedly require more work, but would allow for much more dynamic mocks.
I am a big fan of Apiary.io for a mocking an API before moving to a real server.
You could also use flat .json files and read them from the file system.
You could also use publicly accessible API's like Twitter, Flickr, etc.
Here are some other great resources about Retrofit.
Slides: https://docs.google.com/presentation/d/12Eb8OPI0PDisCjWne9-0qlXvp_-R4HmqVCjigOIgwfY/edit#slide=id.p
Video: http://www.youtube.com/watch?v=UtM06W51pPw&feature=g-user-u
Example Project: https://github.com/dustin-graham/ucad_twitter_retrofit_sample
You can also use something like Webservermock from Squareup! --> https://github.com/square/okhttp/tree/master/mockwebserver
First,create your Retrofit interface.
public interface LifeKitServerService {
/**
* query event list from server,convert Retrofit's Call to RxJava's Observerable
*
* #return Observable<HttpResult<List<Event>>> event list from server,and it has been convert to Obseverable
*/
#GET("api/event")
Observable<HttpResult<List<Event>>> getEventList();
}
Your Requester in follow:
public final class HomeDataRequester {
public static final String TAG = HomeDataRequester.class.getSimpleName();
public static final String SERVER_ADDRESS = BuildConfig.DATA_SERVER_ADDR + "/";
private LifeKitServerService mServerService;
private HomeDataRequester() {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//using okhttp3 interceptor fake response.
.addInterceptor(new MockHomeDataInterceptor())
.build();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(SERVER_ADDRESS)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
//using okhttp3 inteception to fake response.
mServerService = retrofit.create(LifeKitServerService.class);
//Second choice,use MockRetrofit to fake data.
//NetworkBehavior behavior = NetworkBehavior.create();
//MockRetrofit mockRetrofit = new MockRetrofit.Builder(retrofit)
// .networkBehavior(behavior)
// .build();
//mServerService = new MockLifeKitServerService(
// mockRetrofit.create(LifeKitServerService.class));
}
public static HomeDataRequester getInstance() {
return InstanceHolder.sInstance;
}
public void getEventList(Subscriber<HttpResult<List<Event>>> subscriber) {
mServerService.getEventList()
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
}
If you using the second choice(use Retrofit interface to Mock server data),you need to MockRetrofit,use code follow:
public final class MockLifeKitServerService implements LifeKitServerService {
public static final String TAG = MockLifeKitServerService.class.getSimpleName();
private BehaviorDelegate<LifeKitServerService> mDelegate;
private Gson mGson = new Gson();
public MockLifeKitServerService(BehaviorDelegate<LifeKitServerService> delegate) {
mDelegate = delegate;
}
#Override
public Observable<HttpResult<List<Event>>> getEventList() {
List<Event> eventList = MockDataGenerator.generateEventList();
HttpResult<List<Event>> httpResult = new HttpResult<>();
httpResult.setCode(200);
httpResult.setData(eventList);
LogUtil.json(TAG, mGson.toJson(httpResult));
String text = MockDataGenerator.getMockDataFromJsonFile("server/EventList.json");
if (TextUtils.isEmpty(text)) {
text = mGson.toJson(httpResult);
}
LogUtil.d(TAG, "Text:\n" + text);
text = mGson.toJson(httpResult);
return mDelegate.returningResponse(text).getEventList();
}
4.My data is from asset file(Asset/server/EventList.json),this file content is:
{
"code": 200,
"data": [
{
"uuid": "e4beb3c8-3468-11e6-a07d-005056a05722",
"title": "title",
"image": "http://image.jpg",
"goal": 1500000,
"current": 51233,
"hot": true,
"completed": false,
"createdAt": "2016-06-15T04:00:00.000Z"
}
]
}
5.If you are using okhttp3 interceptor,you need to self-defined interceptor,like this:
public final class MockHomeDataInterceptor implements Interceptor {
public static final String TAG = MockHomeDataInterceptor.class.getSimpleName();
#Override
public Response intercept(Chain chain) throws IOException {
Response response = null;
String path = chain.request().url().uri().getPath();
LogUtil.d(TAG, "intercept: path=" + path);
response = interceptRequestWhenDebug(chain, path);
if (null == response) {
LogUtil.i(TAG, "intercept: null == response");
response = chain.proceed(chain.request());
}
return response;
}
private Response interceptRequestWhenDebug(Chain chain, String path) {
Response response = null;
if (BuildConfig.DEBUG) {
Request request = chain.request();
if (path.equalsIgnoreCase("/api/event")) {
//get event list
response = getMockEventListResponse(request);
}
}
private Response getMockEventListResponse(Request request) {
Response response;
String data = MockDataGenerator.getMockDataFromJsonFile("server/EventList.json");
response = getHttpSuccessResponse(request, data);
return response;
}
private Response getHttpSuccessResponse(Request request, String dataJson) {
Response response;
if (TextUtils.isEmpty(dataJson)) {
LogUtil.w(TAG, "getHttpSuccessResponse: dataJson is empty!");
response = new Response.Builder()
.code(500)
.protocol(Protocol.HTTP_1_0)
.request(request)
//protocol&request be set,otherwise will be exception.
.build();
} else {
response = new Response.Builder()
.code(200)
.message(dataJson)
.request(request)
.protocol(Protocol.HTTP_1_0)
.addHeader("Content-Type", "application/json")
.body(ResponseBody.create(MediaType.parse("application/json"), dataJson))
.build();
}
return response;
}
}
6.Finally,you can request your server with code:
mHomeDataRequester.getEventList(new Subscriber<HttpResult<List<Event>>>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
LogUtil.e(TAG, "onError: ", e);
if (mView != null) {
mView.onEventListLoadFailed();
}
}
#Override
public void onNext(HttpResult<List<Event>> httpResult) {
//Your json result will be convert by Gson and return in here!!!
});
}
Thanks for reading.
Adding to the answer by #Alec, I have extended the mock client to get the response directly from a text file in asset folder depending on the request URL.
Ex
#POST("/activate")
public void activate(#Body Request reqdata, Callback callback);
Here the mock client, understands that the URL being fired is activate and looks for a file named activate.txt in the assets folder.
It reads the content from assets/activate.txt file and sends it as response for the API.
Here is the extended MockClient
public class MockClient implements Client {
Context context;
MockClient(Context context) {
this.context = context;
}
#Override
public Response execute(Request request) throws IOException {
Uri uri = Uri.parse(request.getUrl());
Log.d("MOCK SERVER", "fetching uri: " + uri.toString());
String filename = uri.getPath();
filename = filename.substring(filename.lastIndexOf('/') + 1).split("?")[0];
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
InputStream is = context.getAssets().open(filename.toLowerCase() + ".txt");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String responseString = new String(buffer);
return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes()));
}
}
For a detailed explanation you can checkout my blog
http://www.cumulations.com/blogs/13/Mock-API-response-in-Retrofit-using-custom-clients
Mockery (disclaimer: I’m the author) was designed just for this exactly task.
Mockery is a mocking/testing library focused on validating networking layers with built-in support for Retrofit. It auto-generates JUnit tests based on the specs of a given Api. The idea is not to have to write manually any test; neither implementing interfaces for mocking server responses.
For me the custom Retrofit Client is great because of flexibility. Especially when you use any DI framework you can fast and simple turn on/off mock. I am using custom Client provided by Dagger also in unit and integration tests.
Edit:
Here you find example of mocking retrofit
https://github.com/pawelByszewski/retrofitmock

JSON Null Poiner Exception

I got such a very strange problem. I already created weather application which using this API. Problem is that, when i am calling "CONDITION" object,than i am getting a null pointer exception.But when i am calling another object,than everything is fine! Its weird. During 2 weeks this API worked fine,but starting from yesterday, not. Can anyone explain me,why it is like that, and what i have to do. Because application is already finished, and i am making the another one, and i don't want to rewriting this application just because of that problem.
I put my response in another application, to check maybe the problem was in my application,not in the API. Here is the code..
API CLASS:
public interface WeatherAPI {
#GET("/v1/current.json?key=fe1c9cd3fd2d4b189c010010172505")
Call<Weather> getForecastWeather(
#Query("q") String cityName
// #Query("days")Integer days
);
}
CONTROLLER CLASS:
public class Controller {
static final String BASE_WEATHER_URL = "https://api.apixu.com/";
public static WeatherAPI getApi(){
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_WEATHER_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
WeatherAPI weatherAPI = retrofit.create(WeatherAPI.class);
return weatherAPI;
}
}
MAIN ACTIVITY CLASS:
mWeatherAPI = Controller.getApi();
mWeatherAPI.getForecastWeather("Paris").enqueue(new Callback<Weather>() {
#Override
public void onResponse(Call<Weather> call, Response<Weather> response) {
String description = response.body().getCurrent().getCondition().getIcon();
Log.e("TAG", "description: " + description);
}
#Override
public void onFailure(Call<Weather> call, Throwable t) {
Log.e("TAG", "onFailure: " + t.getMessage());
}
});
Yes, you need to add OkHttpClient to your Retrofit:
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
Retrofit retrofit = Retrofit.Builder().baseUrl(yourBaseUrlString)
.addConverterFactory(GsonConverterFactory.create())
.retrofitBuilder.client(okHttpClientBuilder.build()).build();
Check the json Object whether u created or not.

Retrofit2.0 is returning 404 not found

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://ipAdress/SaveImg/DouBanGirl")
.addConverterFactory(GsonConverterFactory.create())
.build();
imgApi imgService = retrofit.create(imgApi.class);
Call<Img> imgCall = imgService.getImg("20151119");
imgCall.enqueue(new Callback<Img>() {
#Override
public void onResponse(retrofit.Response<Img> response, Retrofit retrofit) {
Log.d(TAG, response.code() + " ");
}
#Override
public void onFailure(Throwable t) {
Log.d(TAG, t.getMessage());
}
});
}
public interface imgApi {
#GET("/DouBanGirl")
Call<Img> getImg(#Query("date") String date);
}
when i tried this, it is showing 404 not found. the url is correct, i checked that.
I dont know what going on.
Due to how Retrofit 2.0 uses Http Resolve for resolving the uri scheme of your endpoints, if you specify the baseurl like this http://hello.com and the endpoint URL as /world/foo it will break.
You need to use base URL http://hello.com/ and endpoint URL world/foo.
The / makes the difference.

How to get simple JSON object in Retrofit 2.0.0 beta 1?

I am trying to convert this simple response that looks like this
{
"field_one": "bearer",
"field_two": "fgh",
"field_three": 0
}
I am using latest version of Retrofit 2.0.0-beta1. I never used Retrofit before. There are many tutorials and example of old version of Retrofit. I tried different techniques that works with older versions but thats not working with latest one. Due to lack of documentation of latest version of Retrofit I could not find solution.
I want to use latest version.
Here is POJO
public class Auth {
#SerializedName("field_one")
#Expose
private String fieldOne;
#SerializedName("field_two")
#Expose
private String fieldTwo;
#SerializedName("field_three")
#Expose
private Integer fieldThree;
// setter and getter etc. etc.
}
Here is Interface that I am using
interface Authorization {
#Headers("Authorization: This is some header")
#GET("api/v1/mytoken")
Call<Auth> getToken();
}
This is the way I am calling service
OkHttpClient client = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://myendpoint.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
Authorization serviceAuthorization = retrofit.create(Authorization.class);
serviceAuthorization.getToken().enqueue(new Callback<Auth>() {
#Override
public void onResponse(Response<Auth> response) {
Log.d("Response", ">>> "+ response.toString());
}
#Override
public void onFailure(Throwable t) {
Log.d("fail", ">>> "+ t.getMessage());
}
});
I am unable to get output. It just print this
Response: >>> retrofit.Response#2567e2c3
I want to get data in Auth Object that I will use later.
Please suggest me best solution
Thanks!
I guess that you are not seeing you are expecting to see your object printed out on this line --
Log.d("Response", ">>> "+ response.toString());
That is going to call the toString method on the response. If you want to call it on your deserialized object, call the body() method first --
if(response.isSuccess()) {
Log.d("Response", ">>> "+ response.body().toString());
} else {
Log.d("Response", "Error - " + response.code())
}

How to obtain the body of a retrofit request when it fails?

I am using RxJava with retrofit. I want to know how can I retrieve the BODY/RAW sent by the request when it fails or success.
This is my controller calling the API:
ChatMessage body = new ChatMessage();
...
//configuration of body variable is omitted.
...
chatController.sendMessage(body).subscribe(this::onSendMessageSuccess, this::onSendMessageError);
And these are the methods to receive the answer:
private void onSendMessageSuccess(ChatRestResponse response) {
// How can I get the "ChatMessage body" sent in at first by the re
}
private void onSendMessageError(Throwable throwable) {
// How can I get the "ChatMessage body" sent in at first by the request
}
I want to know how can I get the ChatMessage class that I used to make the request.
JUST FOR REFERENCES
This is my interface:
#Headers({
"Accept: application/json",
"Content-Type: application/json"
})
#POST(URL)
Observable<ChatRestResponse> sendMessage(
#Header("Authorization") String token,
#Body ChatMessage body);
This is my controller that calls the api:
public Observable<ChatRestResponse> sendMessage(ChatMessage body) {
String accessToken = mPref.getAccesToken();
return mChatApi.sendMessage(accessToken , body)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
Brother On Failure there is no body exists in response. There would be just some code associated with the error it faces. like 404 etc.
But if you are talking about your own server response that is on failed. Like if you login to you account from you app by Retrofit. If you enter wrong credentials, internet and connection with server is all OK, Even then the the response will run the function onResponce() . But here you can check the server internal error that the server will send associated with the type or error.
call.enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
if (response.code == HttpURLConnection.HTTP_OK) {
//All is well
// you can get body here as
String token = responce.body().getToken();
//etc
} else {
//Something went wrong like password etc
//You can check the body here also in case of failure
//Which is due to some internal server error
//because of wrong credentials
//But this response is in failure and also have a body
//I guess this is what u want
String failuerToken = responce.getBody().getAccessToken();
new AlertDialog.Builder(LoginActivity.this)
.setMessage("Invalid Credentials")
.setCancelable(false)
.setPositiveButton("Try Again", null)
.show();
}
}
#Override
public void onFailure(Call call, Throwable t) {
showProgress(false);
new AlertDialog.Builder(LoginActivity.this)
.setMessage("Unable to reach server")
.setCancelable(false)
.setPositiveButton("Try Again", null)
.show();
call.cancel();
}
});
NOTE THAT
LoginResponse
Is my own Class
public class LoginResponse {
#SerializedName("access_token")
#Expose
public String accessToken;
#SerializedName("token_type")
#Expose
public String tokenType;
#SerializedName("expires_in")
#Expose
public Integer expiresIn;
}
UPDATE
Call<LoginResponse> call = apiInterface.Login(requestData);
See I'm sending data by using requestData . The Only Solution to your problem is Make a seperate package name urils, make a class RequestData and put some static variables in it.
public class RequestData {
public static String username;
public static String password;
public static String email;
public static Int age;
//etc
}
Set the variable values like this
RequestData.username = "abcd";
RequestData.password = "abcd";
RequestData.email = "abcd#email.com";
RequestData.age = 20";
Then send the data through the api call.
After failure use this class to access the previous data from it and display it on UI respectively.

Resources