Query Link for Retrofit - java

First post, so sorry if my terminology is unclear.
So I'm using retrofit to GET an array of objects from a link: BASE_URL/todos?userId=1.
When using:
#GET("todos?userId={userId}")
Call<List<ToDoObject>> listTodos(#Query("userId") int userId);
for this retrofit call:
retrofit.Retrofit retrofit = new retrofit.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
BaseServiceAPI service = retrofit.create(BaseServiceAPI.class);
Call<List<ToDoObject>> listToDos = service.listTodos(getUserId());
listToDos.enqueue(new Callback<List<ToDoObject>>() {
#Override
public void onResponse(Response<List<ToDoObject>> response, retrofit.Retrofit retrofit) {
if (response.body() != null) {
for (int i = 0; i < response.body().size(); i++) {
toDoObjectList.add(response.body().get(i));
}
toDoRecycAdapter.notifyDataSetChanged();
}else Log.d("flow", "no go");
}
#Override
public void onFailure(Throwable t) {
Log.d("flow", "todo failure: " + t.getMessage());
}
});
to get this array:
[
{
"completed": false,
"dueDate": "2016-07-31 06:38:00",
"id": 1,
"title": "Find your son Duke",
"userId": 1
},
{
"completed": false,
"dueDate": "2017-05-24 07:30:00",
"id": 4,
"title": "Rule the City ",
"userId": 1
},
{
"completed": true,
"dueDate": "2016-1-30 1:15:00",
"id": 6,
"title": "Run The ",
"userId": 1
},
{
"completed": true,
"dueDate": "2016-1-30 1:28:00",
"id": 7,
"title": "Hmmm",
"userId": 1
}
]
I receive this error: "FATAL EXCEPTION: Caused by: java.lang.IllegalArgumentException: URL query string "userId={userId}" must not have replace block. For dynamic query parameters use #Query."
I thought this was the proper case to use Query. I even tried Path but still nothing. I don't know many other programmers to ask and I've been at this for weeks. Can someone tell me what I'm doing wrong please??
Thanks in advance

You should just leave #Query parameter in your request and remove it from #GET. Also you say that you need to request only specific object, so why your response contains the list Call<List<ToDoObject>>?
#GET("todos")
Call<ToDoObject> specificTodo(#Query("userId") int userId);

Related

How to customize error messages for JSONSchema?

Is there a way to provide a custom error message depending on the given condition?
I'm using https://github.com/networknt/json-schema-validator, version 1.0.43
This is my JSON Schema:
{
"$id": "https://configurations/provider.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Configuration",
"type": "object",
"properties": {
"provider": {
"description": "Name of the provider.",
"enum": [
"Provider #1",
"Provider #2"
]
},
"configuration": {
"$schema": "json-schema/configurations/configuration.json"
}
},
"if": {
"properties": {
"parcsProvider": {
"const": "Provider #1"
}
}
},
"then": {
"required": [
"configuration"
]
},
"else": {
"not": {
"required": [
"configuration"
]
}
}
}
If the value for the provider is "Provider #1" then the configuration object is required, and if it's "Provider #2" and configuration is passed an error will occur. I want to customize that error so that the response is the same as it is now but with a custom message like "Provider 2 can't have a configuration."
Current error message/response:
{
"timestamp": "2020-11-23T12:50:56.20658+01:00",
"message": "invalid.json.input",
"validationErrors": [
{
"field": "$",
"message": "$: should not be valid to the schema \"not\" : {\"required\":[\"configuration\"]}"
}
]
}
I had a similar requirement to implement in one of my projects. For validation, I was using https://github.com/everit-org/json-schema.
Here is what I did
Categorized all kind of errors[there must be some specific keyword] thrown by the validator
Now once you have all the keys, you can easily manipulate the errors and send the custom error/response.
Below are the keys I have collected for different cases, this might help you -
MIN_LENGTH_VIOLATION = "expected minLength"
MAX_LENGTH_VIOLATION = "expected maxLength"
PATTERN_VIOLATION = "does not match pattern"
DATA_TYPE_VIOLATION = "expected type"
DEPENDENCY_VIOLATION = "is required"
FORMAT_VIOLATION_OR_ENUM_VALIDATION_VIOLATION = "is not a valid"
MANDATORY_FIELD_VIOLATION_OR_CONDITIONAL_VIOLATION = "required key"
NUMBER_IS_LESS_THAN_VIOLATION = "is not greater or equal to"
NUMBER_IS_GREATER_THAN_VIOLATION = "is not less or equal"
EXCLUSIVE_NUMBER_IS_GREATER_THAN_VIOLATION = "is not less than"
EXCLUSIVE_NUMBER_IS_LESS_THAN_VIOLATION = "is not greater than"
MULTIPLE_OF_VIOLATION = "is not a multiple"
Sample Code -
private static void validate(JSONObject request) {
try {
// Schema, that might be fetched dynamically from some data source
JSONObject schema = new JSONObject();
Schema loadedSchema = SchemaLoader.load(schema);
loadedSchema.validate(request);
} catch (ValidationException ve) {
List<String> allErrorMessages = ve.getAllMessages();
List<String> mandatoryFields = parseMandatoryField(allErrorMessages);
if (CollectionUtils.isNotEmpty(mandatoryFields)) {
throw new MandFieldMissingExp(mandatoryFields);
} else {
List<String> invalidFields = parseInvalids(allErrorMessages);
throw new InvalidFieldExp(invalidFields);
}
}
}
private static List<String> parseMandatoryField(List<String> validationExceptionMessages) {
Set<String> mandatoryListSet = new HashSet<>();
validationExceptionMessages.forEach(errorMessage -> {
if (StringUtils.containsAny(errorMessage, MANDATORY_FIELD_VIOLATION_OR_CONDITIONAL_VIOLATION, DEPENDENCY_VIOLATION)) {
mandatoryListSet.add(StringUtils.substring(errorMessage, errorMessage.indexOf('[') + 1, errorMessage.indexOf(']')));
}
});
return new ArrayList<>(mandatoryListSet);
}
private static List<String> parseInvalids(List<String> validationExceptionMessages) {
Set<String> invalidParamsSet = new HashSet<>();
validationExceptionMessages.forEach(errorMessage -> {
if (StringUtils.containsAny(errorMessage, MIN_LENGTH_VIOLATION, MAX_LENGTH_VIOLATION, PATTERN_VIOLATION,
FORMAT_VIOLATION_OR_ENUM_VALIDATION_VIOLATION, DATA_TYPE_VIOLATION, NUMBER_IS_LESS_THAN_VIOLATION,
MULTIPLE_OF_VIOLATION, EXCLUSIVE_NUMBER_IS_GREATER_THAN_VIOLATION, NUMBER_IS_GREATER_THAN_VIOLATION
, EXCLUSIVE_NUMBER_IS_LESS_THAN_VIOLATION)) {
invalidParamsSet.add(StringUtils.substring(errorMessage, errorMessage.indexOf('/') + 1, errorMessage.indexOf(':')));
}
});
return new ArrayList<>(invalidParamsSet);
}
Hope it helps

Concat a string with a function to get a JSON output

I just started using java for a project, and I have this doubt. I'm trying to get a JSON answer with this code, but I don't know how to concatenate a string with a function in Java Spring. I have this controller, with this result:
public class BbController {
#Autowired
BbService bbService;
private static final String RESP_SUCCESS = "{\"result\" : { \"status\": true, \"http_code\" : 200, \"info\": \"list successfully obtained.\"}}";
#RequestMapping(value= "/all", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAllContracts() {
return RESP_SUCCESS + ",{" + this.bbService.getAllContracts() + "}";
}
}
<---------- RESULT --------->>>
{
"result": {
"status": true,
"http_code": 200,
"info": "list successfully obtained."
}
},
{
[com.example.entity.BbEntity#3ddd5cfb, com.example.entity.BbEntity#1a57ff51
]
}
Without the concatenation and just returning return this.bbService.getAllContracts(), the output would be
[
{
"id": 12345,
"id_client": 123,
"n_contracts": 2,
"default_number": 2
},
{
"id": 1,
"id_client": 12,
"n_contracts": 2,
"default_number": 2
}
]
My service would be
public class BbService {
#Autowired
BbDao bbDao;
public List<BbEntity> getAllContracts(){
return this.bbDao.findAll();
}
}
Is there any way to get this result?
{
"result": {
"status": true,
"http_code": 200,
"info": "list successfully obtained."
}
},
{
[
{
"id": 12345,
"id_client": 123,
"n_contracts": 2,
"default_number": 2
},
{
"id": 1,
"id_client": 12,
"n_contracts": 2,
"default_number": 2
}
]
}
Thanks in advance
Looks like this.bbService.getAllContracts() returns a class that does not implement toString(), therefor it gets this ugly default print, you can implement it to get the better represenataion that you want.
But I think the better solution should not be to fix the toString, but rather to change the return value of your method from a string to some class you create. If you're using spring, it will be serialized into json once you do it
if this.bbService.getAllContracts() , getAllContracts() returns the class it self, it will be autamatically serialized into Json.

ZOMATO - INVALID API Key error in Eclipse but in POSTMAN response is a success

I am executing a GET request of the ZOMATO API the POSTMAN tool returns a successfull response, however when I try with Eclipse it returns the below message :
403 Error
Invalid API Key
The API key am using in POSTMAN and Eclipse are the same have double checked.
The eclipse code is as stated below:
public class exampleTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
RestAssured.baseURI = "https://developers.zomato.com";
Response res = given().
param("user-key", <api_key>).
when().
get("/api/v2.1/categories").
then().assertThat().statusCode(400).and().contentType(ContentType.JSON).extract().response();
In POSTMAN tool am passing the key in the header rather the URL and response is a success as below:
{
"categories": [
{
"categories": {
"id": 1,
"name": "Delivery"
}
},
{
"categories": {
"id": 2,
"name": "Dine-out"
}
},
{
"categories": {
"id": 3,
"name": "Nightlife"
}
},
{
"categories": {
"id": 4,
"name": "Catching-up"
}
},
{
"categories": {
"id": 5,
"name": "Takeaway"
}
},
{
"categories": {
"id": 6,
"name": "Cafes"
}
},
{
"categories": {
"id": 7,
"name": "Daily Menus"
}
},
{
"categories": {
"id": 8,
"name": "Breakfast"
}
},
{
"categories": {
"id": 9,
"name": "Lunch"
}
},
{
"categories": {
"id": 10,
"name": "Dinner"
}
},
{
"categories": {
"id": 11,
"name": "Pubs & Bars"
}
},
{
"categories": {
"id": 13,
"name": "Pocket Friendly Delivery"
}
},
{
"categories": {
"id": 14,
"name": "Clubs & Lounges"
}
}
]
}
I had this error just try this it will work,
instead of using user-key just use apikey.
developers.zomato.com/api/v2.1/categories?apikey=your API key
Good luck.
You're passing the api key as a query param in RestAssured. It should be passed as a header param. Like this:
.header("user-key", <api_key>)
For me, it worked with by using headers instead of header function call.
RequestSpecification requestSpec=RestAssured.given().headers("Content-Type","application/json","user-key",<api-key>);

parsing data from JSON using Volley in Android

I tried parsing JSON data from "https://api.instagram.com/v1/media/popular?client_id="
+ clientId; or any other url, in a tons of different ways! Used couple of JSONParsers, tutorials, readers .. everything, but still can't to get anything from those urls. Now I am using Volley library and still can't get it to work, here is my code and everything you need, if anyone has any ideas , please share them.
public void LoadPictures() {
mRequestQueue = Volley.newRequestQueue(this);
mRequestQueue.add(new JsonObjectRequest(urlInst, null,
new Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
parseJSON(response);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
}));
this is my parseJSON method:
private void parseJSON(JSONObject json) throws JSONException{
// JSONObject value = json.getJSONObject("value");
JSONArray items = json.getJSONArray("data");
for(int i=0;i<items.length();i++) {
JSONObject c=(JSONObject) items.get(i);
JSONObject user = c.getJSONObject("user");
String name= user.getString("username");
JSONObject img=c.getJSONObject("images");
JSONObject thum=img.getJSONObject("thumbnail");
String urlOfPic = thum.getString("url");
PhotoInst photoData=new PhotoInst (i, urlOfPic, name);
photos.add(photoData);
}
this is JSON data I was supposed to get :
"data": [{
"type": "image",
"users_in_photo": [],
"filter": "Gotham",
"tags": [],
"comments": { ... },
"caption": {
"created_time": "1296656006",
"text": "ãã¼ãâ¥ã¢ããªå§ãã¦ä½¿ã£ã¦ã¿ãã(^^)",
"from": {
"username": "cocomiin",
"full_name": "",
"type": "user",
"id": "1127272"
},
"id": "26329105"
},
"likes": {
"count": 35,
"data": [{
"username": "mikeyk",
"full_name": "Kevin S",
"id": "4",
"profile_picture": "..."
}, {...subset of likers...}]
},
"link": "http://instagr.am/p/BV5v_/",
"user": {
"username": "cocomiin",
"full_name": "Cocomiin",
"profile_picture": "http://distillery.s3.amazonaws.com/profiles/profile_1127272_75sq_1296145633.jpg",
"id": "1127272"
},
"created_time": "1296655883",
"images": {
"low_resolution": {
"url": "http://distillery.s3.amazonaws.com/media/2011/02/01/34d027f155204a1f98dde38649a752ad_6.jpg",
"width": 306,
"height": 306
},
"thumbnail": {
"url": "http://distillery.s3.amazonaws.com/media/2011/02/01/34d027f155204a1f98dde38649a752ad_5.jpg",
"width": 150,
"height": 150
},
"standard_resolution": {
"url": "http://distillery.s3.amazonaws.com/media/2011/02/01/34d027f155204a1f98dde38649a752ad_7.jpg",
"width": 612,
"height": 612
}
},
"id": "22518783",
"location": null
},
when I try putting random Toasts to see where is the problem, I can see the onResponse in my method LoadPictures isn't called at all? Where am I failing ? am I just overseeing something small or something else?
#Mate - As visible from your json, you are getting a JsonArray i.e. "data". Hence, change your Listener to Listener<JSONArray> whihc ensures that it returns a JSONArray object. As a result your onResponse will now become,
#Override
public void onResponse(JSONArray response) {
try {
parseJSON(response);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Let me know if this works.
A few things you should verify first:
Are you sure you have the following in your manifest?
<uses-permission android:name="android.permission.INTERNET" />
Instagram requires some sort of API Key / authentication. Are you sure you are providing this?
Is your ErrorListener printing a stack trace? If it is, can you provide it?
That is where I would start.
may this help you response = response.substring(5); makes to remove first 5 characters like data: and continue with JSONArray jsonArray = new JSONArray(response);

Parsing Facebook Graph API response

I'm working on Facebook Scores API for an android app. I query for the user score by accessing the user graph:
https://graph.facebook.com/user_id/scores&access_token={user_access_token}
I get a response like:
{
"data": [
{
"user": {
"name": "Michał Szydłowski",
"id": "100001699654797"
},
"score": 1200,
"application": {
"name": "QuizzlePeople",
"namespace": "quizzlepeople",
"id": "176694722487191"
}
},
{
"user": {
"name": "Michał Szydłowski",
"id": "100001699654797"
},
"score": 1,
"application": {
"name": "Friend Smash!",
"namespace": "friendsmashsample",
"id": "480369938658210"
}
},
{
"user": {
"name": "Michał Szydłowski",
"id": "100001699654797"
},
"score": 0,
"application": {
"name": "Wordox",
"namespace": "wordox-the-game",
"id": "227993680602156"
}
},
{
"user": {
"name": "Michał Szydłowski",
"id": "100001699654797"
},
"score": 0,
"application": {
"name": "SongPop",
"namespace": "songpop",
"id": "323595464361460"
}
}
]
}
How do I extract useful data from this?
I'm trying to take something as a JSONObject, using:
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("https://graph.facebook.com/me?fields=score&access_token=" + token);
HttpResponse resp = client.execute(get);
Log.i("info1", resp.toString());
// Parse the response
HttpEntity responseEntity = resp.getEntity();
String response = EntityUtils.toString(responseEntity);
Log.i("info1", response);
JSONObject result = new JSONObject(response);
JSONArray arr = result.getJSONArray("data");
Log.i("info2", arr.toString());
just to see if I can take anything, say, the array named 'data'. Yet the logcat does not show me anything. It shows the first 2 logs, but not the 3rd. Any ideas?
That looks like JSONObject. You can loop thru it and do whatever you wish with the data.
Have a look at http://json.org/ for documentation for a specific language (I presume you need java so click on the java link).
I appended the data to a table to give you an idea ( jquery / javascript ):
fiddle:http://jsfiddle.net/H8LNB/4/

Categories