How to use Volley to fetch recipes from spoonacular API for an android application. I am new to APIs and would like some help in fetching recipes from the spoonacular api for a list of ingredients specified in an android app.
Step 1
dependencies {
...
implementation 'com.android.volley:volley:1.0.0'
}
Step 2
In AndroidManifest file add permission
<uses-permission android:name="android.permission.INTERNET"/>
Step 3 Add following in MyApplication class
private RequestQueue requestQueue;
public RequestQueue getRequestQueue() {
if (requestQueue == null)
requestQueue = Volley.newRequestQueue(getApplicationContext());
return requestQueue;
}
public void addToRequestQueue(Request request, String tag) {
request.setTag(tag);
getRequestQueue().add(request);
}
public void cancelAllRequests(String tag) {
getRequestQueue().cancelAll(tag);
}
Step 4 Final Step
//URL of the request we are sending
String url = "https://api.spoonacular.com/food/products/22347";
/*
JsonObjectRequest takes in five paramaters
Request Type - This specifies the type of the request eg: GET,
URL - This String param specifies the Request URL
JSONObject - This parameter takes in the POST parameters.null in case of
GET request
Listener -This parameter takes in a implementation of Response.Listener()
interface which is invoked if the request is successful
Listener -This parameter takes in a implemention of Error.Listener()
interface which is invoked if any error is encountered while processing
the request
*/
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
url, null,
new Response.Listener() {
#Override
public void onResponse(JSONObject response) {
//Success Callback
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Failure Callback
}
});
// Adding the request to the queue along with a unique string tag
MyApplication.getInstance().addToRequestQueue(jsonObjectReq, "getRequest");
Something like that. Let's try. Thanks
Related
For any 4xx or 5xx response given out by my micronaut server, I'd like to log the response status code and endpoint it targeted. It looks like a filter would be a good place for this, but I can't seem to figure out how to plug into the onError handling
for instance, this filter
#Filter("/**")
class RequestLoggerFilter: OncePerRequestHttpServerFilter() {
companion object {
private val log = LogManager.getLogger(RequestLoggerFilter::class.java)
}
override fun doFilterOnce(request: HttpRequest<*>, chain: ServerFilterChain): Publisher<MutableHttpResponse<*>>? {
return Publishers.then(chain.proceed(request), ResponseLogger(request))
}
class ResponseLogger(private val request: HttpRequest<*>): Consumer<MutableHttpResponse<*>> {
override fun accept(response: MutableHttpResponse<*>) {
log.info("Status: ${response.status.code} Endpoint: ${request.path}")
}
}
}
only logs on a successful response and not on 4xx or 5xx responses.
How would i get this to hook into the onError handling?
You could do the following. Create your own ApplicationException ( extends RuntimeException), there you could handle your application errors and in particular how they result into http error codes. You exception could hold the status code as well.
Example:
class BadRequestException extends ApplicationException {
public HttpStatus getStatus() {
return HttpStatus.BAD_REQUEST;
}
}
You could have multiple of this ExceptionHandler for different purposes.
#Slf4j
#Produces
#Singleton
#Requires(classes = {ApplicationException.class, ExceptionHandler.class})
public class ApplicationExceptionHandler implements ExceptionHandler<ApplicationException, HttpResponse> {
#Override
public HttpResponse handle(final HttpRequest request, final ApplicationException exception) {
log.error("Application exception message={}, cause={}", exception.getMessage(), exception.getCause());
final String message = exception.getMessage();
final String code = exception.getClass().getSimpleName();
final ErrorCode error = new ErrorCode(message, code);
log.info("Status: ${exception.getStatus())} Endpoint: ${request.path}")
return HttpResponse.status(exception.getStatus()).body(error);
}
}
If you are trying to handle Micronaut native exceptions like 400 (Bad Request) produced by ConstraintExceptionHandler you will need to Replace the beans to do that.
I've posted example here how to handle ConstraintExceptionHandler.
If you want to only handle responses itself you could use this mapping each response code (example on #Controller so not sure if it works elsewhere even with global flag:
#Error(status = HttpStatus.NOT_FOUND, global = true)
public HttpResponse notFound(HttpRequest request) {
<...>
}
Example from Micronaut documentation.
Below code I used for adding custom cors headers in the error responses, in doOnError you can log errors
#Filter("/**")
public class ResponseCORSAdder implements HttpServerFilter {
#Override
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
return this.trace(request)
.switchMap(aBoolean -> chain.proceed(request))
.doOnError(error -> {
if (error instanceof MutableHttpResponse<?>) {
MutableHttpResponse<?> res = (MutableHttpResponse<?>) error;
addCorsHeaders(res);
}
})
.doOnNext(res -> addCorsHeaders(res));
}
private MutableHttpResponse<?> addCorsHeaders(MutableHttpResponse<?> res) {
return res
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "OPTIONS,POST,GET")
.header("Access-Control-Allow-Credentials", "true");
}
private Flowable<Boolean> trace(HttpRequest<?> request) {
return Flowable.fromCallable(() -> {
// trace logic here, potentially performing I/O
return true;
}).subscribeOn(Schedulers.io());
}
}
I am trying to upload file using QBCustomObjectFiles ,uploading starts to show progress in log cat ,but with file field is null and response throws error like this '{"errors":["The resource wasn't found"]}'
I checked My Note Class on Quickblox admin panel,everything seems OK.Also I checked the file (field in method parameter) and it is not null as showing in log cat
public void uploadNote(Note note, File file,
QBEntityCallback<QBCustomObjectFileField> callback, QBProgressCallback
progressCallback) {
QBCustomObject customObject = new QBCustomObject();
customObject.setClassName(Note.Contract.CLASS_NAME_NOTE);
customObject.put(Note.Contract.COURSE_ID,note.getCourseId());
customObject.put(Note.Contract.CATEGORY_ID,note.getCategoryId());
customObject.put(Note.Contract.DESCRIPTION,note.getDescription());
customObject.put(Note.Contract.TOPIC,note.getTopic());
QBCustomObjectsFiles.uploadFile(file, customObject, "noteFile", progressCallback).performAsync(callback);
}
This is my log cat :
REQUEST
POST https://api.quickblox.com/data/Note/null/file.json
HEADERS
QuickBlox-REST-API-Version=0.1.1
QB-SDK=Android 3.9.1
QB-Token=011a2bc55be67185d4d045d8b2d31
PARAMETERS
field_name=noteFile
INLINE
POST https://api.quickblox.com/data/Note/null/file.json?field_name=noteFile
and this is response
'{"errors":["The resource wasn't found"]}'
The Uploading starts and shows progress ,but after progress 100 it throws above error.
You should use QBContent instead of QBCustomObjectsFiles. Example:
QBContent.uploadFileTask(file, isPublic, tags, new QBProgressCallback() {
#Override
public void onProgressUpdate(int progressValue) {
//some code for progress
}
}).performAsync(new QBEntityCallback<QBFile>() {
#Override
public void onSuccess(QBFile qbFile, Bundle params) {
//some code for success upload
}
#Override
public void onError(QBResponseException responseException) {
//some code for error upload
}
});
I am attempting to modify my dependent tests so they are ran in a specific way and have yet find a way possible. For instance, say I have the following two tests and the defined data provider:
#Dataprovider(name = "apiResponses")
Public void queryApi(){
return getApiResponses().entrySet().stream().map(response -> new Object[]{response.getKey(), response.getValue()}).toArray(Object[][]::new);
}
#Test(dataprovider = "apiResponses")
Public void validateApiResponse(Object apiRequest, Object apiResponse){
if(apiResponse.statusCode != 200){
Assert.fail("Api Response must be that of a 200 to continue testing");
}
}
#Test(dataprovider = "apiResponses", dependsOnMethod="validateApiResponse")
Public void validateResponseContent(Object apiRequest, Object apiResponse){
//The following method contains the necessary assertions for validating api repsonse content
validateApiResponseData(apiResponse);
}
Say I have 100 api requests I want to validate, with the above, if a single one of those 100 requests were to return a status code of anything other than 200, then validateResponseContent would be skipped for all 100. What I'm attempting to achieve is that the dependent tests would be skipped for only the api responses that were to return without a status code of 200 and for all tests to be ran for responses that returned WITH a status code of 200.
You should be using a TestNG Factory which creates instances with both the apiRequest and apiResponse in it for each instance. Now each instance would basically first run an assertion on the status code before it moves on to validating the actual api response.
Here's a sample that shows how this would look like:
public class TestClassSample {
private Object apiRequest, apiResponse;
#Factory(dataProvider = "apiResponses")
public TestClassSample(Object apiRequest, Object apiResponse) {
this.apiRequest = apiRequest;
this.apiResponse = apiResponse;
}
#Test
public void validateApiResponse() {
Assert.assertEquals(apiResponse.statusCode, 200, "Api Response must be that of a 200 to continue testing");
}
#Test(dependsOnMethods = "validateApiResponse")
public void validateResponseContent() {
//The following method contains the necessary assertions for validating api repsonse content
validateApiResponseData(apiResponse);
}
#DataProvider(name = "apiResponses")
public static java.lang.Object[][] queryApi() {
return getApiResponses().entrySet()
.stream().map(
response -> new java.lang.Object[]{
response.getKey(), response.getValue()
})
.toArray(Object[][]::new);
}
}
Would'nt adding a if/else block solve this?
#Test(dataprovider = "apiResponses")
Public void validateApiResponse(Object apiRequest, Object apiResponse){
if(apiResponse.statusCode != 200){
Assert.fail("Api Response must be that of a 200 to continue testing");
} else {
validateApiResponseData(apiResponse);
}
}
i wrote a normal html login form, that forwards to a vaadin project, where i want to receive the username and password and check if its valid. but i have problems getting this request.
when i add a requesthandler in the init() method of my UI class, i can only get the request data after the second call of the vaadin page (because at the first call of init, the hander ist not added yet)
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(new MainComponent());
VaadinSession.getCurrent().addRequestHandler(
new RequestHandler() {
#Override
public boolean handleRequest(VaadinSession vaadinSession, VaadinRequest vaadinRequest, VaadinResponse vaadinResponse) throws IOException {
String username = vaadinRequest.getParameter("username");
return false;
}
});
so i tried to overwrite the VaadinServlet method doPost, but it does not get triggered. when i overwrite the methode service(HttpServletRequest request, HttpServletResponse response), this method is triggered a serval times for each request, so also not a good place to get just the userdata.
so whats the right way to solve this problem?
i dont't know if this is the best solution, but at least it works. maybe this helps someone.
here a short explanation what i do. i retrieve the posted username and password from the post values of my plain html login formular from another url and see if it is existing in the database. if it exists, it returns the result, otherwise the value ERROR.
i extended the VaadinServlet and overwrote the method service like this
#Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.service(request, response);
String username = request.getParameter("username");
if(username != null) { // called several times, only set when username is returned, otherwise the value remains "error"
String password = request.getParameter("password");
this.result = getResult(username, Encrypter.encryp(password));
}
}
and this is inside my class extended from UI
#Override
protected void init(VaadinRequest vaadinRequest) {
MyServlet myServlet = (MyServlet) VaadinServlet.getCurrent();
String result = myServlet.getResult();
if(result .equals(MyServlet.ERROR)){ // check if the result set in the servlet is valid, otherwise forward to the loginpage
goToLogin();
myServlet.resetResult();
return;
}
myServlet.resetResult();
...
}
To whom it may concern - obtaining request and response in Vaadin 8 (which might be also available in Vaadin 7):
VaadinServletRequest vsRequest = (VaadinServletRequest) VaadinService.getCurrentRequest ();
HttpServletRequest httpServletRequest = vsRequest.getHttpServletRequest ();
VaadinServletResponse vsResponse = (VaadinServletResponse) VaadinService.getCurrentResponse ();
HttpServletResponse httpServletResponse = vsResponse.getHttpServletResponse ();
You can read the request parameter directly through the VaadinRequest object that's passed into init():
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(new MainComponent());
String username = vaadinRequest.getParameter("username");
}
It work for me perfect:
User is my simple class with username, name etc.
setting logged user in session:
public void setLoggedUser(User loggedUser) {
this.loggedUser = loggedUser;
getUI().getSession().getSession().setAttribute("loggedUser", loggedUser);
}
reading user:
loggedUser = (User) getUI().getSession().getSession().getAttribute("loggedUser"); //return null if not logged in
We have two RESTful APIs - one is internal and another one is public, the two being implemented by different jars. The public API sort of wraps the internal one, performing the following steps:
Do some work
Call internal API
Do some work
Return the response to the user
It may happen (though not necessarily) that the two jars run in the same Java process.
We are using Restlet with the JAX-RS extension.
Here is an example of a simple public API implementation, which just forwards to the internal API:
#PUT
#Path("abc")
public MyResult method1(#Context UriInfo uriInfo, InputStream body) throws Exception {
String url = uriInfo.getAbsolutePath().toString().replace("/api/", "/internalapi/");
RestletClientResponse<MyResult> reply = WebClient.put(url, body, MyResult.class);
RestletUtils.addResponseHeaders(reply.responseHeaders);
return reply.returnObject;
}
Where WebClient.put is:
public class WebClient {
public static <T> RestletClientResponse<T> put(String url, Object body, Class<T> returnType) throws Exception {
Response restletResponse = Response.getCurrent();
ClientResource resource = new ClientResource(url);
Representation reply = null;
try {
Client timeoutClient = new Client(Protocol.HTTP);
timeoutClient.setConnectTimeout(30000);
resource.setNext(timeoutClient);
reply = resource.put(body, MediaType.APPLICATION_JSON);
T result = new JacksonConverter().toObject(new JacksonRepresentation<T>(reply, returnType), returnType, resource);
Status status = resource.getStatus();
return new RestletClientResponse<T>(result, (Form)resource.getResponseAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS), status);
} finally {
if (reply != null) {
reply.release();
}
resource.release();
Response.setCurrent(restletResponse);
}
}
}
and RestletClientResponse<T> is:
public class RestletClientResponse<T> {
public T returnObject = null;
public Form responseHeaders = null;
public Status status = null;
public RestletClientResponse(T returnObject, Form responseHeaders, Status status) {
this.returnObject = returnObject;
this.responseHeaders = responseHeaders;
this.status = status;
}
}
and RestletUtils.addResponseHeaders is:
public class RestletUtils {
public static void addResponseHeader(String key, Object value) {
Form responseHeaders = (Form)org.restlet.Response.getCurrent().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
if (responseHeaders == null) {
responseHeaders = new Form();
org.restlet.Response.getCurrent().getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders);
}
responseHeaders.add(key, value.toString());
}
public static void addResponseHeaders(Form responseHeaders) {
for (String headerKey : responseHeaders.getNames()) {
RestletUtils.addResponseHeader(headerKey, responseHeaders.getValues(headerKey));
}
}
}
The problem is that if the two jars run in the same Java process, then an exception thrown from the internal API is not routed to the JAX-RS exception mapper of the internal API - the exception propagates up to the public API and is translated to the Internal Server Error (500).
Which means I am doing it wrong. So, my question is how do I invoke the internal RESTful API from within the public API implementation given the constraint that both the client and the server may run in the same Java process.
Surely, there are other problems, but I have a feeling that fixing the one I have just described is going to fix others as well.
The problem has nothing to do with the fact that both internal and public JARs are in the same JVM. They are perfectly separated by WebResource.put() method, which creates a new HTTP session. So, an exception in the internal API doesn't propagate to the public API.
The internal server error in the public API is caused by the post-processing mechanism, which interprets the output of the internal API and crashes for some reason. Don't blame the internal API, it is perfectly isolated and can't cause any troubles (even though it's in the same JVM).