I'm working on an Android application that uses Retrofit to create a restful client. In order to debug networks calls, I would like to display or dump the url that's actually being invoked. Is there a way to do this? I've included some code below which shows how the app currently using retrofit.
Client interface definition:
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.GET;
import retrofit.http.Headers;
import retrofit.http.POST;
import retrofit.http.Path;
// etc...
public interface MyApiClient {
#Headers({
"Connection: close"
})
#GET("/{userId}/{itemId}/getCost.do")
public void get(#Path("userId") String userId, #Path("itemId") String userId, Callback<Score> callback);
//....etc
}
Service which uses generated client:
// etc...
import javax.inject.Inject;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
#Inject
MyApiClient myApiClient;
// etc...
myApiClient.getCost(myId, itemId, new Callback<Cost>() {
#Override
public void success(Cost cost, Response response) {
Log.d("Success: %s", String.valueOf(cost.cost));
if (cost.cost != -1) {
processFoundCost(cost);
} else {
processMissingCost(itemId);
}
stopTask();
}
#Override
public void failure(RetrofitError error) {
handleFailure(new CostFailedEvent(), null);
}
});
}
call.request().url(), where call is type of retrofit2.Call.
RetrofitError has a getUrl() method that returns the URL.
Also the Response has a getUrl() method as well within the callback.
That, and you can also specify the log level as per this question:
RestAdapter adapter = (new RestAdapter.Builder()).
//...
setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG"))
Although based on the docs, LogLevel.BASIC should do what you need.
BASIC
Log only the request method and URL and the response status code and execution time.
Yes, you can enable debug logging by calling setLogLevel() on your RestAdapter.
I typically set logging to LogLevel.FULL for debug builds like so:
RestAdapter adapter = builder.setEndpoint("example.com")
.setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)
.build();
This will automatically print out all of the information associated with your HTTP requests, including the URL you are hitting, the headers, and the body of both the request and the response.
Related
I have a couple of spring boot rest controllers, and I want a standard JSON response structure to be sent to the client.
The standard response will be composed of responseTime, apiResponseCode, status, apiName, response ( which will vary based on the api). See below:
{
"responseTime": "2020-04-19T08:36:53.001",
"responseStatus": "SUCCESS",
"apiResponseCode": "SUCCESS",
"apiName": "PROPERTY_STORE_GET_PROPERTIES",
"response": [
{
"propertyName": "app.name",
"propertyValue": "property-store"
}
]
}
To achieve this, I have created below model class:
package com.example.response.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.example.constants.ApiResponseCode;
import com.example.constants.Status;
public class ApplicationResponse<T> implements Serializable {
private static final long serialVersionUID = -1715864978199998776L;
LocalDateTime responseTime;
Status responseStatus;
ApiResponseCode apiResponseCode;
String apiName;
T response;
public ApplicationResponse(LocalDateTime responseTime, Status status,
ApiResponseCode apiRespCode, String apiName, T response) {
this.responseTime = responseTime;
this.responseStatus = status;
this.apiResponseCode = apiRespCode;
this.apiName = apiName;
this.response = response;
}
// getters and setters
To create a generic response wrapper, I have created below response util class.
import java.time.LocalDateTime;
import com.example.constants.ApiResponseCode;
import com.example.constants.Status;
import com.example.response.model.ApplicationResponse;
public class ResponseUtil {
public static <T> ApplicationResponse<T> createApplicationResponse(String
apiName, T response) {
return new ApplicationResponse<>(LocalDateTime.now(),
Status.SUCCESS, ApiResponseCode.SUCCESS, apiName,
response);
}
private ResponseUtil() {
}
}
Now the ask is that my response from controller should get serialized in the standard way. Shown below is my controller method.
package com.example.propertystore.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestController;
import com.example.constants.ApiResponseCode;
import com.example.constants.Status;
import com.example.exception.ApplicationException;
import com.example.exception.ApplicationExceptionHelper;
import com.example.propertystore.constants.PropertyStoreApiName;
import com.example.propertystore.dto.PropertyDTO;
import com.example.propertystore.entity.Property;
import com.example.propertystore.service.PropertyStoreService;
import com.example.response.ResponseUtil;
import com.example.response.model.ApplicationResponse;
#RestController
public class PropertyStoreControllerImpl implements PropertyStoreController {
#Autowired
PropertyStoreService propertyStoreService;
#Autowired
ApplicationExceptionHelper exceptionHelper;
#Override
public ApplicationResponse<List<PropertyDTO>> getProperties() throws ApplicationException {
ApplicationResponse<List<PropertyDTO>> response = null;
try {
response = ResponseUtil.createApplicationResponse(
PropertyStoreApiName.PROPERTY_STORE_GET_PROPERTIES.toString(),
propertyStoreService.getProperties());
} catch (Exception e) {
exceptionHelper.raiseApplicationException( HttpStatus.INTERNAL_SERVER_ERROR, Status.FAILURE,
ApiResponseCode.INTERNAL_SERVER_ERROR,
PropertyStoreApiName.PROPERTY_STORE_GET_PROPERTIES.toString(), null);
}
return response;
}}
With the current implementation what I'll have to do is that in my controllers I will have to transform the response by calling ResponseUtil.createApplicationResponse(). This is going to litter the entire controller methods with the createApplicationResponse() method call.
What I wanted to explore is that if there is any cleaner way of achieving this using servlet filters or AOP?
PS: I tried filter option, but couldn't understand how to proceed around it. Got stuck after retrieving the response.getOutputStream() in doFilter().
Hope someone can help?
Just wrap all your responses into a decorator object.
class ResponseDecorator<T> {
//global.fields (time,code, status.....)
T response;
}
Then wrap this response wrapper into the ResponseEntity
The response.getOutputStream that you used and filters are servlet related classes , and i think you can do that without them.Just make your custom response class and add fields however you want your response. Than in the controller , just return new ResponseEntity(HttpStatus.OK,"your message "):
I don't know if this is the behavior you want.
I am trying to send an array of strings using axios to a rest endpoint using jersey with spring boot and tomcat. It results in a 404 and I am clueless. The url being passed is correct because if I send a single string with GET it works correctly.
EDIT: Any exception within any another endpoint (say NullPointerException) also results in 404 being shown in the browser. This is something to do with the configuration. So 404 is kind of a red herring status code.
This is my java side code
import org.springframework.stereotype.Component;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.*;
#Component
#Path("v1/")
public class SomeResourceV1 {
#POST
#Path("delete")
#Consumes(MediaType.APPLICATION_JSON)
public void deleteFoo(List<String> ids) {
if (ids != null) {
// do something
}
}
}
This is the typescript code:
public delete(someIds : string[]) {
axios({
method: 'POST',
url: "/v1/delete",
data: someIds
}).then((response : any) => {
}).catch((error) => {
console.log("*** delete error ***", error);
});
}
I have also tried to send data as
data:{
ids: someIds
}
I have also attempted to use transformRequest but to no avail.
How does I fix this? Thanks for the help!
Using the AWS Java SDK, I am trying to determine if a PUT request results in the creation of a new object or update of an existing object, without making a second REST API call.
My initial thought was to see if a different status code is returned. Unfortunately I don't see a way to access the HTTP response status code from PutObjectResult.
While looking at the SDK docs I found ObjectMetadata.getLastModified(). Unfortunately it returns null every time I use it.
This is the code I am using to troubleshoot this:
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.PutObjectResult;
public class Main {
public static void main(String[] args) {
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.build();
try {
PutObjectResult result = s3Client.putObject("pail", "foo", "first");
System.out.println(result.getMetadata().getLastModified());
} catch (AmazonServiceException e) {
System.out.println(e.getStatusCode() + " " + e.getErrorMessage());
}
}
}
After the first PUT request:
After the second PUT request:
For context, I created a bucket specifically for this with default settings and no items.
Any idea why getLastModified returns null or even how to access HTTP response status codes from PutObjectResult?
I'm trying to create an Error Resource that will show the exact same view for all 300-599 error codes. I've got it mostly working, with the exception of erroneous POST requests. The error I get is,
WARN [2017-09-06 23:56:51,475] org.eclipse.jetty.server.handler.ErrorHandler: Error page loop /error
It seems like something is off in my ErrorResource logic, but I can't seem to put my finger on it.
Here is the ErrorResource class...
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import com.project.views.ErrorView;
import java.net.URI;
#Path("/error/")
#Produces(MediaType.TEXT_HTML)
public class ErrorResource {
private String appName;
#Context
UriInfo uri;
public ErrorResource(String appName) {
this.appName = appName;
}
#POST
public Response errorPost() {
URI redirectUri = uri.getBaseUri();
return Response.seeOther(redirectUri).build();
}
#GET
public ErrorView error() {
return new ErrorView(appName);
}
#GET
#Path("/404/")
public Response error404() {
return Response.status(404).entity(new ErrorView(appName)).build();
}
}
The errorPost() function is what's giving me trouble. The idea was to do at 301 redirect back to the same page, ostensibly performing a GET request which gets caught by the regular error() function. My Application Class shows that I'm registering the error handler to catch all 300-599's...
public class WebAppApplication extends Application<WebAppConfiguration> {
public static void main(String[] args) throws Exception {
new WebAppApplication().run(args);
}
#Override
public void initialize(Bootstrap<WebAppConfiguration> bootstrap) {
bootstrap.addBundle(new AssetsBundle("/www", "/static"));
bootstrap.addBundle(new ViewBundle());
}
#Override
public void run(WebAppConfiguration config, Environment environment) {
/* Error Handling */
ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
errorHandler.addErrorPage(300,403,"/error");
errorHandler.addErrorPage(404, "/error/404");
errorHandler.addErrorPage(405,599,"/error");
/* Resources */
final HomeResource homeResource = new HomeResource(config.getAppName());
final ErrorResource errorResource = new ErrorResource(config.getAppName());
/* Environment Registration */
environment.getApplicationContext().setErrorHandler(errorHandler);
environment.jersey().register(homeResource);
}
}
And nothing too crazy in the Error view
public class ErrorView extends View {
private String appName;
public ErrorView(String appName) {
super("pageError.mustache");
this.appName = appName;
}
public String getAppName() {
return XSS.htmlEncode(appName);
}
}
The ErrorView mustache template only really contains a message, the navbar, and meta refresh HTML tag.
<meta http-equiv="refresh" content="10; url=/" />
But issuing an erronous POST request to the "/input/" (or any) endpoint throws that "page loop" error, and returns this in the browser...
Browser Screenshot:
Making this a catch-all error message would help to keep the code base clean, will be helpful to the user, and maintains the website branding even in a unexpected failure.
I appreciate any insight the community might have, and preemptive "thank you" for the advice!
I have a put method that accepts inputstream. I want to call this method using rest assured in JUnit.
This is what I used:
with().body(inpustream).put("/service/1"); // i got error 404 forbidden.
POST will return status code 201 and PUT will return 200, and POST will create a new resource but, PUT will update the existing resource. This means we will have to mention which resource we wish to update in the URI itself like below.
import io.restassured.RestAssured;
import static io.restassured.RestAssured.*;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.hamcrest.Matchers.*;
public class PUTMethod {
public static Map<String, String> map = new HashMap<String, String>();
#BeforeTest
public void putdata(){
map.put("userId", "2");
map.put("id", "19");
map.put("title", "this is projectdebug.com");
map.put("body", "i am testing REST api with REST-Assured and sending a PUT request.");
RestAssured.baseURI = "http://jsonplaceholder.typicode.com";
RestAssured.basePath = "/posts/";
}
#Test
public void testPUT(){
given()
.contentType("application/json")
.body(map)
.when()
.put("/100")
.then()
.statusCode(200)
.and()
.body("title", equalTo("this is projectdebug.com"));
}
}
Visit http://www.projectdebug.com/send-put-request-using-rest-assured/
for more information.
Actually, you are doing well but sending multipart through PUT is unsecured and is quite random (https://jira.spring.io/browse/SPR-9079). Amend your spring-security.xml to add a filter or use POST method in this case.
You can also try your code by calling another PUT webservice with no stream.
(And what is the error code ? 404 or 403 ?)
A similar problem solved by using MultipartFilter : Spring 3.0 FileUpload only with POST?
Have a look at the following example, where it explains how to use PUT request using Rest Assured:
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static com.jayway.restassured.RestAssured.*;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.Response;
public class GetStatusCodeTest {
#BeforeClass
public void setBaseUri () {
RestAssured.baseURI = "https://localhost:3000";
}
#Test
public void updateUsingPut () {
Posts post = new Posts();
post.setId ("3");
post.setTitle ("Hello Bhutan");
post.setAuthor ("StaffWriter");
given().body (post)
.when ()
.contentType (ContentType.JSON)
.put ("/posts/3");
}
}
For detailed explanation, you may check out the following link:
https://restservicestesting.blogspot.in/2016/10/automating-put-request-using-rest.html