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!
Related
i try to display simple error massage for the unavailable resource of my service model by extending my class with RuntimeException but didn't display
TodoService Implementation
#Override
public String retrieveTodoStatusById(Long id) {
Optional<String> optionalTodo = Optional.ofNullable(todoRepository.findStatusById(id));
System.out.println("OptionalTodo " +optionalTodo );
String status = optionalTodo.orElseThrow(TodoNotFoundException::new);
return status;
}
TodoNotFoundException
package mang.io.todosrestapi.exceptionhandler;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
#ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Todo not available")
public class TodoNotFoundException extends RuntimeException{
public TodoNotFoundException(){
}
public TodoNotFoundException(String message){
super(message);
}
}
default error with no message is display
Every time i run the exception error message is not display
How can display the error message?
Try to add this line in your application.properties file:
server.error.include-message=always
I'm learning to create a REST Assured and Cucumber framework from scratch following a tutorial video on Youtube.
Below is the step definition and the method it calls in the RestAssuredExtension class.
#Given("^I perform GET operation for \"([^\"]*)\"$")
public void i_Perform_GET_Operation_For(String url) throws Throwable {
RestAssuredExtension.GetOps(url);
}
package utilities;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import io.restassured.response.ResponseOptions;
import io.restassured.specification.RequestSpecification;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
public class RestAssuredExtension {
public static RequestSpecification Request;
public RestAssuredExtension() {
//Arrange
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://localhost:3000/");
builder.setContentType(ContentType.JSON);
var requestSpec = builder.build();
Request = RestAssured.given().spec(requestSpec);
}
public static ResponseOptions<Response> GetOps(String url) {
//Act
try {
return Request.get(new URI(url));
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}
In the video tutorial, the test passes successfully. But when I run the test myself, it results in the following error:
Step failed
java.lang.NullPointerException: Cannot invoke "io.restassured.specification.RequestSpecification.get(java.net.URI)" because "utilities.RestAssuredExtension.Request" is null
at utilities.RestAssuredExtension.GetOps(RestAssuredExtension.java:42)
at steps.GETPostSteps.i_Perform_GET_Operation_For(GETPostSteps.java:21)
Any takers please?
From the example you have given, I think you have not initialized the RestAssuredExtension.Request field.
In the video (I quickly skimmed it), they provide a hook to create a new instance of the RestAssuredExtension before any tests are executed. This will ensure that the public static class variable Request will have been initialized to a non-null value.
My recommendation, if you want to reduce dependency for setup on the test framework and make use of static methods:
public final class RequestExtension {
private static RequestSpecification request;
// Ensure that no one is able to create an instance and thereby bypass proper initalization
private RequestExtension() {
}
// Ensures the initialization responsibility is within the class itself and not a hidden dependency for other users.
private static void getInstance() {
if (request == null) {
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://localhost:3000/");
builder.setContentType(ContentType.JSON);
var requestSpec = builder.build();
request = RestAssured.given().spec(requestSpec);
}
return request;
}
public static ResponseOptions<Response> GetOps(String url) {
// Initialize
getInstance();
// Act
try {
return request.get(new URI(url));
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}
Otherwise, mixing static methods with dependencies on the instance will keep tripping people up. Would go either with the above or remove static from the class altogether:
public class RequestExtension {
private RequestSpecification request;
public RestAssuredExtension() {
//Arrange
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setBaseUri("http://localhost:3000/");
builder.setContentType(ContentType.JSON);
var requestSpec = builder.build();
request = RestAssured.given().spec(requestSpec);
}
public ResponseOptions<Response> GetOps(String url) {
//Act
try {
return request.get(new URI(url));
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}
One thing to help with debugging is to follow Java naming conventions. The capitalisation of your class field RequestSpecification makes it read as a class not a field name. (Request vs request) It was the same in the video so its a source issue. :)
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.
Intellij keeps saying Undefined Step when running my feature file. However, I have copied the steps and put them into another package and added that package name in the "glue" parameter for Edit configurations. Still not working.
I've added the feature file and it doesn't show any missing step references. I am adding a screenshot. I have added all the steps in another package.
Please see below
The code for CountriesSteps is as follows
package Steps;
import Fixtures.Countries;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import org.junit.Assert;
public class CountriesSteps {
Countries countriesclass = new Countries();
#Given("^I generate a restful request for countries$")
public void iGenerateARestfulRequestForCountries() throws Throwable {
countriesclass.GetCountries();
}
#When("^I receive a successful country response (.*)$")
public void iReceiveASuccessfulCountryResponseResponse(int code) throws Throwable {
Assert.assertEquals(code, countriesclass.getsCode());
}
#When("^I receive a successful country response$")
public void iReceiveASuccessfulCountryResponse() throws Throwable {
Assert.assertEquals(200, countriesclass.getsCode());
}
#Then("^the api country response returns (.*)$")
public void theApiCountryResponseReturnsCountries(int countries) throws Throwable {
Assert.assertEquals(countries, countriesclass.getCount());
}
#Then("^the api country response returns (.*),(.*),(.*),(.*),(.*)$")
public void theApiCountryResponseReturnsCountriesNameCapitalPopulation(int countries, int index, String name, String capital, int population) throws Throwable {
Assert.assertEquals(countries, countriesclass.getCount());
}
#Then("^the api country response for Index (.*) returns (.*),(.*),(.*)$")
public void theApiCountryResponseForIndexIndexReturnsNameCapitalPopulation(int index, String name, String capital, int population) throws Throwable {
//Validate a few values from response
Assert.assertEquals(name, countriesclass.getcList().get(index).name);
Assert.assertEquals(capital, countriesclass.getcList().get(index).capital);
Assert.assertEquals(population, countriesclass.getcList().get(index).population);
}
}
And code for Countries is
package Fixtures;
import Models.CountriesData;
import com.jayway.restassured.response.Response;
import gherkin.deps.com.google.gson.Gson;
import gherkin.deps.com.google.gson.reflect.TypeToken;
import org.json.JSONArray;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import static com.jayway.restassured.RestAssured.get;
public class Countries {
private static String url;
private static int count;
private static int sCode;
private static List<CountriesData> cList;
public void GetCountries() throws Exception
{
try {
url = "http://restcountries.eu/rest/v1/all";
// make get request to fetch json response from restcountries
Response resp = get(url);
//Fetching response in JSON as a string then convert to JSON Array
JSONArray jsonResponse = new JSONArray(resp.asString());
count = jsonResponse.length(); // how many items in the array
sCode = resp.statusCode(); // status code of 200
//create new arraylist to match CountriesData
List<CountriesData> cDataList = new ArrayList<CountriesData>();
Gson gson = new Gson();
Type listType = new TypeToken<List<CountriesData>>() {}.getType();
cDataList = gson.fromJson(jsonResponse.toString(), listType);
cList = cDataList;
}
catch (Exception e)
{
System.out.println("There is an error connecting to the API: " + e);
e.getStackTrace();
}
}
//getters to return ('get) the values
public int getsCode() {
return sCode;
}
public int getCount() {
return count;
}
public List<CountriesData> getcList() {
return cList;
}
}
When creating a new step definition file, IntelliJ by default proposes file path of \IdeaProjects\RestAPI\src\main\resources\stepmethods.
Your step definition folder is \IdeaProjects\RestAPI\src\test\java\Steps. Make sure cucumber isn't looking in the wrong place.
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.