This question already has answers here:
How to POST raw whole JSON in the body of a Retrofit request?
(27 answers)
Closed 6 years ago.
I've seen this questions many times and tried many solutions but without resolving my problem, I'm trying to send a json in a POST request using retrofit, I'm not an expert in programming so I may miss something obvious.
My JSON is in a string and looks like that:
{"id":1,"nom":"Hydrogène","slug":"hydrogene"}
My Interface (called APIService.java) looks like that:
#POST("{TableName}/{ID}/update/0.0")
Call<String> cl_updateData(#Path("TableName") String TableName, #Path("ID") String ID);
And my ClientServiceGenerator.java looks like that:
public class ClientServiceGenerator{
private static OkHttpClient httpClient = new OkHttpClient();
public static <S> S createService(Class<S> serviceClass, String URL) {
Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.client(httpClient).build();
return retrofit.create(serviceClass);
}}
And finally here is the code in my activity
APIService client = ClientServiceGenerator.createService(APIService.class, "http://mysiteexample.com/api.php/");
Call<String> call = client.cl_updateData("atomes", "1");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response, Retrofit retrofit) {
if (response.code() == 200 && response.body() != null){
Log.e("sd", "OK");
}else{
Log.e("Err", response.message()+" : "+response.raw().toString());
}
}
#Override
public void onFailure(Throwable t) {
AlertDialog alertError = QuickToolsBox.simpleAlert(EditDataActivity.this, "updateFail", t.getMessage(), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
alertError.show();
}
});
Tell me if you need anything else, hope someone could help me.
EDIT
Didn't mention it first time but my JSON won't always be with the same keys (id, nom, slug).
First you need to create an object to represent the json you need:
public class Data {
int id;
String nom;
String slug;
public Data(int id, String nom, String slug) {
this.id = id;
this.nom = nom;
this.slug = slug;
}
}
Then, modify your service to be able to send this object:
#POST("{TableName}/{ID}/update/0.0")
Call<String> cl_updateData(#Path("TableName") String TableName, #Path("ID") String ID, #Body Data data);
Finally, pass this object:
Call<String> call = client.cl_updateData("atomes", "1", new Data(1, "Hydrogène", "hydrogene"));
UPD
To be able to send any data use Object instead of Data:
#POST("{TableName}/{ID}/update/0.0")
Call<String> cl_updateData(#Path("TableName") String TableName, #Path("ID") String ID,
#Body Object data);
Related
I want to call an api endpoint and display the associated response in my android app.
The api takes a parameter user_name and return response of that user.
Response is in json array consisting json of date, location and img (base64).
RESPONSE
[
{
"id": "602a1901a54781517ecb717c",
"date": "2021-02-15T06:47:29.191000",
"location": "mall",
"img": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCgoKBggLDAsKDAkKCgr/2wBDAQICAgICAgUDAwUKBwYHCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgr/wAARCASvBLADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/
}
]
the issue I am facing is I am not able to store the response and parse it.
I am using retrofit for this.
There is no issue in the api call the server gets a successfull request the issue is in the client side (android app).
Here is the code that i currently have.
ApiInterface.java
interface ApiInterface {
#FormUrlEncoded
#POST("end_point")
Call<List<Task>>getstatus(#Field("user_name") String user_name);
}
Task.java
public class Task {
#SerializedName("user_name")
public String user_name;
public Task(String user_name) {
user_name = user_name.substring(1, user_name.length()-1);
this.user_name= user_name;
}
public String getUser() {
return user_name;
}
}
MainActivity.java
private void LoginRetrofit(String user_name) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")
.addConverterFactory(GsonConverterFactory.create())
.build();
final ApiInterface request = retrofit.create(ApiInterface.class);
Call<List<Task>> call = request.getstatus(user_name);
Toast.makeText(getApplicationContext(), "user_name" + " " + call.request(), Toast.LENGTH_LONG).show();
call.enqueue(new Callback<List<Task>>() {
#Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
try {
List<Task> rs=response.body();
Toast.makeText(getApplicationContext(), "Response" + " "+rs, Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
Log.d("REsponse error",e.getMessage());
}
}
#Override
public void onFailure(Call<List<Task>> call, Throwable t) {
Log.d("Error",t.getMessage());
}
});
}
This is the response which is being returned.
In MainActivity.java file, update the code as below as you are printing rs object in your toast message, it prints only the object address not the value in it. So to print the value of the object you received, you must call the methods of the object to get value like as.
MainActivity.java
private void LoginRetrofit(String user_name) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")
.addConverterFactory(GsonConverterFactory.create())
.build();
...
call.enqueue(new Callback<List<Task>>() {
#Override
public void onResponse(Call<List<Task>> call, Response<List<Task>> response) {
try {
List<Task> rs=response.body();
if(rs.size() > 0){
Task user = rs.get(0);
String id = user.getId();
String location = user.getLocation();
Toast.makeText(getApplicationContext(),"Response : Id="+id+" and location="+location, Toast.LENGTH_LONG).show();
}
}
catch (Exception e)
{
Log.d("REsponse error",e.getMessage());
}
}
...
});
}
and update the Task model as
Task.java
public class Task {
#SerializedName("id") public String id;
#SerializedName("date") public String date;
#SerializedName("location") public String location;
#SerializedName("img") public String img;
public Task(String id, String date, String location, String img) {
this.id=id;
this.date=date;
this.location=location;
this.img=img;
}
public String getId(){ return this.id; }
public String getDate(){ return this.date; }
public String getLocation(){ return this.location; }
public String getImg(){ return this.img; }
}
Your data model class variables should be serialized or to have names as same as in the response , so that retrofit can be able to bind response values to your model variables .
Also you must have a variable in your model class for each key-value pair in your response that you want to use .
check this example to get how retrofit really work .
I want to get notifications from a server using API. I'm using Retrofit2 to work with API.
The problem is when I'm passing parameter in POST method I'm getting "IllegalArgumentException URL does not contain the parameter."
The parameter is correct and working in iOS. I want to implement in android.
Below is the result when debugging the app.
Caused by: java.lang.IllegalArgumentException: URL
"notification/newnotification" does not contain "{userid}". (parameter #1)
I've tried changing parameters and asked the API developer too. He says parameter is correct.
This is code for API Interface:
public interface API{
#FormUrlEncoded
#POST("notification/newnotification")
Call<ResponseBody> getUserNotification(
#Path("userid") int userid
);
}
RetrofitClient.java
public class RetrofitClient {
public static final String BASE_URL = "http://danceglobe.co/dance/api/";
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient(){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance(){
if(mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public API getApi(){
return retrofit.create(API.class);
}
}
Calling Function from MainActivity
private void getNotification(String currentUserId) {
Call<ResponseBody> call = RetrofitClient.getInstance().getApi().getUserNotification(Integer.parseInt(currentUserId));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(!response.isSuccessful()){
Toast.makeText(MainActivity.this,response.message(),Toast.LENGTH_SHORT).show();
}
try {
String s = response.body().string();
Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
I want it to respond to some data.
Please help me. I got stuck into this from past 2 days.
Caused by: java.lang.IllegalArgumentException: URL
"notification/newnotification" does not contain "{userid}". (parameter #1)
means you should add the userId to the path like
public interface API {
#POST("notification/newnotification/{userid}")
Call<ResponseBody> getUserNotification(
#Path("userid") int userid
);
}
#Path("userid") maps the variable to the placeholder {userid}, that was missing.
I got it working by making some changes in API interface.
Below is new Code for API interface
#FormUrlEncoded
#POST("notification/newnotification")
Call<ResponseBody> getUserNotification(
#Field("userid") String userid // changed line
);
this is my web service for sending and receiving a string value with key
Urls.class
public class Urls {
public static final String MAIN_URL="example.com";
}
API.class
public interface API {
#POST("user.php")
Call<MainResponse> registerUser(#Body User user);
#POST("user.php")
Call<MainResponse>loginUser(#Body User user);
#POST("contact.php")
Call<MainResponse>checkNumber(#Body Phone phone);
}
WebService.class
public class WebService {
private static WebService instance;
private API api;
public WebService() {
OkHttpClient client = new OkHttpClient.Builder().build();
Retrofit retrofit = new Retrofit.Builder().client(client)
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(Urls.MAIN_URL)
.build();
api = retrofit.create(API.class);
}
public static WebService getInstance() {
if (instance == null) {
instance = new WebService();
}
return instance;
}
public API getApi() {
return api;
}
}
MainResponse.class
public class MainResponse {
#SerializedName("status")
public int status;
#SerializedName("message")
public String message;
}
Phone.class
public class Phone {
#SerializedName("phone")
public String phone;
}
MainActivity.class
Phone phone=new Phone();
phone.phone=contactsString[0];
WebService.getInstance().getApi().checkNumber(phone).enqueue(new Callback<MainResponse>() {
#Override
public void onResponse(Call<MainResponse> call, Response<MainResponse> response) {
if (response.body().status==1){
//do something
}
}
#Override
public void onFailure(Call<MainResponse> call, Throwable t) {
}
});
My question is how to edit this to send an array filled with values contactsString[] and receive another array
Your service is in a way to get single request and give you back single response, you should change server side service if you are the backend developer of the service, to get a list of request and give back a list of result
this is your current service:
#POST("contact.php")
Call<MainResponse>checkNumber(#Body Phone phone);
server side developer should change service for you to be able to send in body an object like this for Phones:
public class Phones {
#SerializedName("phones")
public List<String> phones;
}
and in your response you should get list of status and messages with request phones
response like this:
public class MainResponse {
public List<PhoneStatusResponse> phonesStatusList;
}
public class PhoneStatusResponse {
#SerializedName("status")
public int status;
#SerializedName("message")
public String message;
#SerializedName("phoneRequest")
public String phone;
}
I am able to get data from database using retrofit and REST api but facing errors in Posting data. Post works using postman but not through retrofit.I have been unable to locate the error.I have tried changing endpoint, that is, "rest" and "rest/" but still get not found error.
ApiView of Post in Django RESTful api: view.py
def post(self,request):
serializer =table_restSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'results':serializer.data},status=201)
return Response(serializer.errors, status=404)
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^rest',views.restSerializer.as_view())
]
urlpatterns = format_suffix_patterns(urlpatterns)
serializer.py:
class table_restSerializer(serializers.ModelSerializer):
class Meta:
model = table_rest
fields = '__all__'
My android code:
Interface
public interface ApiInterface {
#GET("rest")
Call<CustomViewResponse> getJsonFromSid();
#POST("rest")
Call<CustomViewResponse> createTask(#Body CustomViewHolder task);
}
CustomViewHolder class:
public class CustomViewHolder {
#SerializedName("id")
private Integer id;
#SerializedName("tt")
private String tt;
#SerializedName("varr")
private Integer varr;
#SerializedName("edi")
private String edi;
public CustomViewHolder(String tt, Integer varr, String edi){
this.tt = tt;
this.varr = varr;
this.edi = edi;
}
public Integer getid(){
return id;
}
/*public void setid(Integer id){
this.id = id;
}*/
public String gettt()
{
return tt;
}
public void settt(String tt){
this.tt = tt;
}
public Integer getvarr(){
return varr;
}
public void setvarr(Integer varr){
this.varr = varr;
}
public String getedi(){
return edi;
}
public void setedi(String edi){
this.edi = edi;
}
}
CustomViewResponse class
public class CustomViewResponse {
#SerializedName("results")
private List<CustomViewHolder> results;
public List<CustomViewHolder> getResults(){
return results;
}
}
MainActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.sid_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
ApiInterface apiService1 = ApiClient.getClient().create(ApiInterface.class);
Call<CustomViewResponse> call = apiService.getJsonFromSid();
CustomViewHolder cc = new CustomViewHolder("my task title",22,"a string");
call.enqueue(new Callback<CustomViewResponse>() {
#Override
public void onResponse(Call<CustomViewResponse> call, Response<CustomViewResponse> response) {
int statuscode = response.code();
List<CustomViewHolder> customViewHolders = response.body().getResults();
recyclerView.setAdapter(new AdapterSid(customViewHolders, R.layout.list_item_sid, getApplicationContext()));
}
#Override
public void onFailure(Call<CustomViewResponse> call, Throwable t) {
Log.e("TAG main", t.toString());
}
});
call1.enqueue(new Callback<CustomViewResponse>() {
#Override
public void onResponse(Call<CustomViewResponse> call1, Response<CustomViewResponse> respo) {
int statuscode = respo.code();
Log.d("Message", "code..."+respo.code() + " message..." + respo.message());
CustomViewResponse respon = respo.body();
if (respon == null){
Log.e("Error",""+statuscode+ "......"+ respo.message()+"....null body");
}
}
#Override
public void onFailure(Call<CustomViewResponse> call1, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
Following is my table structure:
class table_rest(models.Model):
tt = models.CharField(max_length=10,default = 12)
varr = models.IntegerField(default=30)
edi = models.CharField(max_length=1000,default='44')
def __str__(self):
return self.tt
Using postman my Json body which gets successfully saved is :
{
"tt": "hello",
"varr": 911,
"edi": "emergency. Can't find solution"
}
Please add an extra URL.
urlpatterns = [
url(r'^admin/', admin.site.urls), # Any URL starting with admin(ex: http://testdomainname.com/admin/xyz)
url(r'^rest/$',views.restSerializer.as_view()), # Any URL starting with only rest(ex: http://testdomainname.com/rest/)
url(r'^$',views.restSerializer.as_view()), # Any empty URL with '' (ex: http://testdomainname.com/)
]
First I included the url pattern as suggested by Dinesh Mandepudi. Then I made changes to my regex in retrofit. It was url issue that I was not confronting when using postman. I just added '/' at the beginning of my post regex.
public interface ApiInterface {
#GET("/rest")
Call<CustomViewResponse> getJsonFromSid();
#POST("/rest/")
Call<CustomViewResponse> createTask(#Body CustomViewHolder task);
}
Also a silly mistake is I was trying to add a string of 13 length in the database column while I had set the limit to 10.
I'm using Robospice with Retrofit ans ORMLite modules. Retrofit part working good. I have City model for Retrofit:
City.java:
public class City {
public int city_id;
public String name;
#SuppressWarnings("serial")
public static class List extends ArrayList<City> {
}
}
I'm taking this model from server by GET-request:
MyApi.java
public interface MyAPI {
#GET("/cities")
City.List getCities();
}
This part works fine by calling this method:
getSpiceManager().execute(mRequestCity, "city", DurationInMillis.ONE_MINUTE, new ListCityRequestListener());
and listener:
public final class ListCityRequestListener implements RequestListener<City.List> {
#Override
public void onRequestFailure(SpiceException spiceException) {
Toast.makeText(RegisterActivity.this, "failure", Toast.LENGTH_SHORT).show();
}
#Override
public void onRequestSuccess(final City.List result) {
Toast.makeText(RegisterActivity.this, "success", Toast.LENGTH_SHORT).show();
updateCities(result);
}
}
At this time i want to download city list once from server and store this list into sqlitedb by ORMLite module. I've created ORMLite model:
City.java
#DatabaseTable(tableName = "city")
public class City {
public final static String DB_CITY_ID_FIELD_NAME = "id";
public final static String DB_CITY_NAME_FIELD_NAME = "name";
#DatabaseField(canBeNull = false, dataType = DataType.INTEGER, columnName = DB_CITY_ID_FIELD_NAME)
int id;
#DatabaseField(canBeNull = false, dataType = DataType.STRING, columnName = DB_CITY_NAME_FIELD_NAME)
private String name;
public City() {
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("id = ").append(id);
sb.append(", ").append("name = ").append(name);
return sb.toString();
}
}
My RetrofitSpiceService.java looks like this:
public class RetrofitSpiceService extends RetrofitGsonSpiceService {
private final static String BASE_URL = "http://example.com/api/v1";
private final static UserFunctions userFunctions = new UserFunctions();
#Override
public CacheManager createCacheManager(Application application) throws CacheCreationException {
CacheManager cacheManager = new CacheManager();
List< Class< ? >> classCollection = new ArrayList< Class< ? >>();
// add persisted classes to class collection
classCollection.add( City.class );
// init
RoboSpiceDatabaseHelper databaseHelper = new RoboSpiceDatabaseHelper( application, "sample_database.db", 1 );
InDatabaseObjectPersisterFactory inDatabaseObjectPersisterFactory = new InDatabaseObjectPersisterFactory( application, databaseHelper, classCollection );
cacheManager.addPersister( inDatabaseObjectPersisterFactory );
return cacheManager;
}
#Override
protected Builder createRestAdapterBuilder() {
Builder mBuilder = super.createRestAdapterBuilder();
mBuilder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
if (userFunctions.isUserLoggedIn()) {
request.addHeader("Authorization", userFunctions.getToken());
}
}
});
return mBuilder;
}
#Override
public void onCreate() {
super.onCreate();
addRetrofitInterface(MyAPI.class);
}
#Override
protected String getServerUrl() {
return BASE_URL;
}
}
I can't understand how can i store and read data from my City database? How do i need to change RetrofitSpiceService? I want download data by Retrofit and store it to database by ORMLite. My CacheManager is correct, i.e. will work properly? Maybe I misunderstand how the module Robospice-ORMLite works?
Thanks a lot!
When you make execute() call with cache key and duration Robospice will store your response into database.
getSpiceManager().execute(mRequestCity, "city", DurationInMillis.ONE_MINUTE, new ListCityRequestListener());
All following requests during one minute will get data from this cache, and then it makes network call. If you want to get data only from cache take a look on getSpiceManager().getFromCache() method. I think it's what you are looking for.