I solved the problem.
I was sending plain-text in the server.
Changed the line to read:
response.writeHead(200, {'Content-Type': 'application/json'});
Quick question. My friend recommended looking into Retrofit rather than using my ASync task for my REST android application. I am having one small problem since I am new to the system. The server runs using Node.js to send JSON objects by means of .stringify() and so when I retrieve an object it is a String rather than a JSON, and I cannot convert it to my List of the appropriate objects. I am guessing the error is due to a cast exception because it is sending a string because I get the exception:
com.google.gson.JsonSyntaxException
Any help would be great. Here is the code I thought would be appropriate.
Android Client Code Example below:
private void requestData() {
RestAdapter adapter = new RestAdapter.Builder().setEndpoint(ENDPOINT).build();
UnitAPI unit_api = adapter.create(UnitAPI.class);
unit_api.getUnits(new Callback<List<Unit>>() {
#Override
public void success(List<Unit> t, Response response) {
units = t;
updateDisplay();
}
#Override
public void failure(RetrofitError error) {
Log.d("Failure UnitGet()", error.getMessage());
}
});
}
Android Unit.class:
public class Unit {
private String ID;
private long bearing;
private long lat;
private long lng;
private String type;
public String getID() {
return ID;
}
public void setID(String ID){
this.ID = ID;
}
public long getBearing() {
return bearing;
}
public void setBearing(long bearing){
this.bearing = bearing;
}
public void setLat(long lat){
this.lat = lat;
}
public long getLat(){
return lat;
}
public void setLng(long lng){
this.lng = lng;
}
public long getLng(){
return lng;
}
public void setType(String type){
this.type = type;
}
public String getType(){
return type;
}
}
The server sends the .json file via the command:
if (method == "GET") {
response.write(JSON.stringify(unitsJSON));
}
Any thoughts on how I can convert it to a list of units from the string on the client side or a json object on the server side?
Thanks!
I solved the problem. I was sending plain-text in the server. Changed the line to read:
response.writeHead(200, {'Content-Type': 'application/json'});
I think you must add json-parser to package using npm
then
in response write
res.end(JSON.stringfy('your resp0onse here'));
Related
I have a problem with Retrofit. I am working on an Android app which needs to get information about a product from Open Food Facts API. I tried with Retrofit, I created a class with the information I want from JSON (I only need a few fields and I didn't want to make a class with all the JSON fields, because there are over 50 I think)
public class Product {
#SerializedName("product_name_en")
private String name;
#SerializedName("brands")
private String company;
#SerializedName("update_key")
private int key;
public String getName() {
return name;
}
public String getCompany() {
return company;
}
public int getKey() {
return key;
}
}
Then I created an interface with the #GET method and the relative URL to the API endpoint
public interface OpenFoodFactsAPI {
#Headers("User-Agent: Fooducate - Android - Version 1.0")
#GET("/api/v0/product/01223004")
Call<Product> getProducts();
}
And inside my fragment I did this
TextView text = view.findViewById(R.id.txt);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://us.openfoodfacts.org")
.addConverterFactory(GsonConverterFactory.create())
.build();
OpenFoodFactsAPI jsonPlaceHolderApi = retrofit.create(OpenFoodFactsAPI.class);
Call<Product> call = jsonPlaceHolderApi.getProducts();
call.enqueue(new Callback<Product>() {
#Override
public void onResponse(Call<Product> call, Response<Product> response) {
if (!response.isSuccessful()) {
text.setText("Code: " + response.code());
return;
}
Product product = response.body();
String content = "";
content += "NAME: " + product.getName() + "\n";
content += "COMPANY: " + product.getCompany() + "\n";
content += "KEY: " + product.getKey() + "\n";
text.append(content);
}
#Override
public void onFailure(Call<Product> call, Throwable t) {
text.setText(t.getMessage());
}
});
I tried the get request on a website and it works. However, in my app an empty response is returned.
You can view the JSON from the api here
If you have any idea about this problem, please answer. Thank you!
From the API you are not getting exactly the Product as response. You are getting another object which is Product is a child object.
You need to create a response Like below,
public class ResponseObject{
#SerializedName("status")
private int status;
#SerializedName("status_verbose")
private String status_verbose;
#SerializedName("product")
private Product product;
//getters and setters goes here
}
then your interface should be like below as you are expecting ResponseObject here.
public interface OpenFoodFactsAPI {
#Headers("User-Agent: Fooducate - Android - Version 1.0")
#GET("/api/v0/product/01223004")
Call<ResponseObject> getProducts();
}
This will solve your problem. Update me If you have any problem with this.
After using
public class ResponseObject{
#SerializedName("status")
private int status;
#SerializedName("status_verbose")
private String status_verbose;
#SerializedName("product")
private Product product;
}
Just change
public int getKey() {return key;}
to
public String getKey() {
return key;
}
Otherwise
Error: java.lang.NumberFormatException: For input string: "ecoscore20210127"
because in json it exists like "update_key": "ecoscore20210127"
I am trying to send one json from my frontend angular project to the backend which is springboot.
It is the first time I am using these 2 technologies so I lack in experience.
I am not quite sure if my http post method in Angular is wrong or if my backend isn't listening to the data which are supposed to come.
I will attach both code parts so that you can help me. Thank you in advance!
Here is a picture of the chrome console:
Http Errorcode 404
http error image
Backend:
#RestController
#RequestMapping
#CrossOrigin(origins = "http://localhost:4200")
public class RequestController {
private RolesRequestRepository rolesRequestRepository;
#PostMapping("/sendrolesrequest")
void addRequest(#RequestBody RolesRequest rolesRequest) {
rolesRequestRepository.save(rolesRequest);
}
#GetMapping("/sendrolesrequest")
public List<RolesRequest> getRequests() {
return (List<RolesRequest>) rolesRequestRepository.findAll();
}
}
#Entity
public class RolesRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String requester = "";
private String recipient = "";
public RolesRequest(String recipient, String requester) {
this.recipient = recipient;
this.requester = requester;
}
public RolesRequest(){
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRequester() {
return requester;
}
public void setRequester(String requester) {
this.requester = requester;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
}
Here is the angular frontend part:
#Injectable()
export class RequestService {
sendRolesRequestUrl = 'sendrolesrequest'; // URL to web api
private handleError: HandleError;
constructor(
private http: HttpClient,
httpErrorHandler: HttpErrorHandler) {
this.handleError = httpErrorHandler.createHandleError('RequestService');
}
sendRolesRequest (rolesRequest: RequestModel): Observable<RequestModel> {
//console.log("addRolesRequest try post:" + rolesRequest.print());
return this.http.post<RequestModel>(this.sendRolesRequestUrl, rolesRequest, httpOptions)
.pipe(
catchError(this.handleError('sendRolesRequest', rolesRequest))
);
}
testPost() {
const headers = new Headers();
headers.append('Content-Type', 'application/json; charset=utf-8');
this.http.post(this.sendRolesRequestUrl, {'key1': 'value1', 'key2': 'value2'}, httpOptions)
.subscribe(() => {}, err => console.error(err));
}
}
export class RequestFormulaComponent implements OnInit {
onSendRequest() {
this.requestService
.sendRolesRequest(this.rolesRequest)
.subscribe();
}
}
I would be very happy if someone helps me out here. I am struggling on this topic over a week.
Is that even the way how a backend application should communicate with the webpage? If not, how can I do it otherwise?
You're using JPA entity as DTO, and have no setters/getters, also there is no default constuctor, modify your RolesRequest like this:
#Entity
public class RolesRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String requester = "";
private String recipient = "";
public RolesRequest() { }
public RolesRequest(String recipient, String requester) {
this.recipient = recipient;
this.requester = requester;
}
public String getRequester() { return this.requester; }
public void setRequester(String r) { this.requester = r;}
public String getRecipient() { return this.recipient; }
public void setRecipient(String r) { this.recipient = r;}
Are your backend and angular app running on the same port? (backend and frontend are combined in the same application)
You are calling http://localhost:4200/sendrolesrequest and I think that's a request on the Angular app itself. You get a HTTP 404 error code (NOT FOUND)
You should call the endpoint of the backend application. It's running on port 8080 for example so call http://localhost:8080/sendrolesrequest (or with other port if backend is running on another port)
Change:
sendRolesRequestUrl = 'sendrolesrequest';
to:
sendRolesRequestUrl = 'http://localhost:8080/sendrolesrequest';
I am using mvp Design pattern in android development and i am using retrofit2 with it ... when i run the function to get me information from a the web it get the information but returns null list
the Response.Body come with response that mean that the code works
the model function
List<SearchDdb> searchResult;
private Context context;
public MainModel(Context context){this.context=context;}
public List<SearchDdb> searchUser(String name) {
final MainPresenter presenter = new MainPresenter(context);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Db db = retrofit.create(Db.class);
Call<List<SearchDdb>> call = db.getUsers(name);
call.enqueue(new Callback<List<SearchDdb>>() {
#Override
public void onResponse(Call<List<SearchDdb>> call, Response<List<SearchDdb>> response) {
if(!response.isSuccessful()){
presenter.showDialog();
}
searchResult = response.body();
}
#Override
public void onFailure(Call<List<SearchDdb>> call, Throwable t) {
}
});
return searchResult;
}
the SearchDdb file
private int id;
private String name;
private String grade;
private String age;
private String address;
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getGrade() {
return grade;
}
public String getAge() {
return age;
}
public String getAddress() {
return address;
}
}
How i call the function
List<SearchDdb> ressult = presenter.searchUser("1");
You cant call it like List<SearchDdb> ressult = presenter.searchUser("1"); because searchUser method makes an async request via retrofit. This way searchUse returns null searchResult because response has not come yet.
Define a LiveData in your viewmodel class and observe it in your activity/fragment. When response comes from api in
onResponse in searchUser post that response to live data and use it where you observe.
If you want to see a tutorial you can look at this article.
Here is another example.
The GET request to tenants/client/{hostname} returns a json object with the property baseApiHostname.
#GET("api/tenants/client/{hostname}")
Call<HostName> getHostname(#Path("hostname") String hostname);
baseApiHostname is successful retrieved. That hostname which is used to create the rest of tenant requests from.
Log.v("base url","testing "+preferenceManager.getTenantHostname());
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(builder.create()))
.baseUrl(preferenceManager.getTenantHostname())
.build();
I received the error "java.lang.IllegalArgumentException: Illegal URL".
stacktrace message
After attaching debugger I realized that hostname = null.
debugger message
Call<HostName> call = hostNameApiService.getHostname(tenant);
call.enqueue(new Callback<HostName>() {
#Override
public void onResponse(Call<HostName> call, Response<HostName> response) {
if (response.isSuccessful()) {
String hostname = response.body().getBaseApiHostname();
preferenceManager.setTenantHostname(hostname);
retrieveCampaign();
} else {
Toast.makeText(StartSurveyActivity.this, "Error Retrieving Hostname", Toast.LENGTH_SHORT).show();
}
}
Here is the Hostname model class
#SerializedName("id")
private String id;
#SerializedName("name")
private String name;
#SerializedName("baseApiHostName")
private String baseApiHostname;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBaseApiHostname() {
return baseApiHostname;
}
public void setBaseApiHostname(String baseApiHostname) {
this.baseApiHostname = baseApiHostname;
}
If there's any other detail required that will aid in helping myself and other developers who may have faced a similar problem, please don't hesistate to ask.
Thanks in advance guys.
GSON is not successfully serializing any response to the field you're retrieving, so there is some misalign in how you are setting up gson to parse your json result.
Given your object and your sample JSON, your field in JSON is "baseApiHostname" whereas in your object your GSON annotation is for serialized name "baseApiHostName".
You are setting null in your Retrofit.Builder for your base URL. What is the URL for your server? You need to set that for the first time. Then you can change it after that if need be but it can't be null the first time.
I have a problem when parsing json by using Retrofit can't get any of data , This URL request array of parameter
https://lao.busnavi.asia/api/location.php?ids%5B%5D=132&ids%5B%5D=133&ids%5B%5D=131
JSON from server that looks like this
json data
My code
LatestBusLocation.java
#SerializedName("id") private int id;
#SerializedName("status") private int status;
#SerializedName("route_id") private String routeId;
#SerializedName("lng") private double lng;
#SerializedName("lat") private double lat;
#SerializedName("accuracy") private double accuracy;
#SerializedName("speed") private double speed;
#SerializedName("heading") private float heading;
#SerializedName("date") private Date date;
Interface class
public interface ApiService {
#POST("location.php")
Call<LatestBusLocation> loadLatestBusLocation(#Query("ids[]") int[] ids);
}
MainActivity.java
int[] ids = {131, 132, 133};
Call<LatestBusLocation> call = HttpManager.getInstance()
.getService().loadLatestBusLocation(ids);
call.enqueue(new Callback<LatestBusLocation>() {
#Override
public void onResponse(Call<LatestBusLocation> call, Response<LatestBusLocation> response) {
Log.e("WorkOrNote1", "Working");
if (response.isSuccessful()) {
dao = response.body();
Log.d("daoResponse", String.valueOf(dao.getId()));
} else {
try {
Log.e("LatestBusLocation", response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<LatestBusLocation> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});
Retrofit fails to map your object because you have specified an LatestBusLocation in the Call. This should be a List<LatestBusLocation>.
Aditionally, you will have to add a deserializer to map correctlly because you are getting an object (with ids keys) instead of a proper array. Look at this relationed answer