Response content-type text/html on server but application/json locally - httpresponse

I am extending the JsonResult class
public class MyRequest : JsonResult
{
private readonly string _statusDescription;
public MyRequest (object data)
: this(data, "My Request")
{
}
public MyRequest (object data, string description)
{
Data = data;
_statusDescription = description;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
context.HttpContext.Response.StatusDescription = _statusDescription;
base.ExecuteResult(context);
}
}
When I use this class locally to return an object I get my json object and content-type = json.
But when I run this on the server I get content-type = text/html. On the server the text value is "My Request" which is the description and there is no json value returned.
Any ideas?

Related

FeignException com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.http.ResponseEntity`

Any Help please !!
I receive this error when I'm calling my endpoint which call Feign in the background :
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of
`org.springframework.http.ResponseEntity` (no Creators, like default constructor, exist): cannot deserialize
from Object value (no delegate- or property-based Creator)
at [Source: (BufferedReader); line: 1, column: 2]
This is my endpoint inside Controller :
#RestController
#RequestMapping(Routes.URI_PREFIX)
public class CartoController {
#Autowired
private ReadCartographyApiDelegate readCartographyApiDelegate;
#GetMapping(value = "/cartographies/{uid}", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseWrapper<ReadCartographyResponse> readCarto(HttpServletRequest request,
#PathVariable(name = "uid") String uid) {
ResponseEntity<ReadCartographyResponse> result ;
try {
result = readCartographyApiDelegate.readCartography(uid);
}catch (Exception e){
throw new TechnicalException("Error during read Carto");
}
return responseWrapperWithIdBuilder.of(result.getBody());
}
}
Interface ReadCartographyApiDelegate generated automatically by openApi from yaml file :
#javax.annotation.Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "...")
public interface ReadCartographyApiDelegate {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
default ResponseEntity<ReadCartographyResponse> readCartography(String uid) {
getRequest().ifPresent(request -> {
for (MediaType mediaType: MediaType.parseMediaTypes(request.getHeader("Accept"))) {
if (mediaType.isCompatibleWith(MediaType.valueOf("application/json"))) {
String exampleString = "null";
ApiUtil.setExampleResponse(request, "application/json", exampleString);
break;
}
}
});
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
This my ReadCartoApiDelegateImpl which implements ReadCartographyApiDelegate interface :
#Service
public class ReadCartographyApiDelegateImpl implements ReadCartographyApiDelegate {
private EcomGtmClient ecomGtmClient;
public ReadCartographyApiDelegateImpl(EcomGtmClient ecomGtmClient) {
this.ecomGtmClient = ecomGtmClient;
}
#Override
public ResponseEntity<ReadCartographyResponse> readCartography(String uid) {
ResponseEntity<ReadCartographyResponse> response = ecomGtmClient.readCartography(uid);
return response;
}
}
This is the feign client :
#FeignClient(name = "ecomGtmSvc", url = "http://localhost/")
public interface EcomGtmClient {
#GetMapping(value = "/read-carto/{uid}")
ResponseEntity<ReadCartographyResponse> readCartography(#PathVariable("uid") String uid);
}
The problem is that ResponseEntity (spring class) class doesn't contain default constructor which is needed during creating of instance. is there Any config to resolve this issue ?
If you want access to the body or headers on feign responses, you should use the feign.Response class. ResponseEntity does not work with feign because it is not meant to. I think it is best if you just return Response from your feign client method. You should then be able to pass the body to the ResponseEntity instance in the Controller.
What is your reason to even use the response-wrapper, i can't really figure that out from your code?
Sadly I couldn't find any documentation on the Response class, but here's the link to the source on GitHub.
https://github.com/OpenFeign/feign/blob/master/core/src/main/java/feign/Response.java
My Suggestion would be
#FeignClient(name = "ecomGtmSvc", url = "http://localhost/")
public interface EcomGtmClient {
#GetMapping(value = "/read-carto/{uid}")
ReadCartographyResponse readCartography(#PathVariable("uid") String uid);
}
#RestController
#RequestMapping(Routes.URI_PREFIX)
public class CartoController {
#Autowired
private ReadCartographyApiDelegate readCartographyApiDelegate;
#GetMapping(value = "/cartographies/{uid}", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseWrapper<ReadCartographyResponse> readCarto(HttpServletRequest request,
#PathVariable(name = "uid") String uid) {
ReadCartographyResponse result ;
try {
result = readCartographyApiDelegate.readCartography(uid);
}catch (Exception e){
throw new TechnicalException("Error during read Carto");
}
// I don't know where you get the builder from, so I assume it does something import and is needed
return responseWrapperWithIdBuilder.of(result);
}
}
Of course you'd also have to change all intermediate classes.
The Response Output was the correct Object that I have to put, cause every time I need to check the status from my feign client endpoint to do différent logic
#FeignClient(name = "ecomGtmSvc", url = "http://localhost/")
public interface EcomGtmClient {
#GetMapping(value = "/read-carto/{uid}")
ReadCartographyResponse readCartography(#PathVariable("uid") String uid);
}

SpringBoot accessing params inside method

New to Spring/SpringBoot, I have two methods like bellow -
1.
#GetMapping("/score")
public UserScoreRes getUserScore(#RequestHeader("api-key") String apiKey,
#RequestHeader("jwt") String jwt,
#RequestParam(name = "date", defaultValue = "2022-07-15") String dateStr) {
.....
}
#GetMapping(value = "/score", params ="behaviour-version=2")
public UserScoreResV2 getUserScoreV2(#RequestHeader("api-key") String apiKey,
#RequestHeader("jwt") String jwt,
#RequestParam(name = "date", defaultValue = "2022-07-15") String dateStr) {
....
}
In method 2 (getUserScoreV2), how can I get behaviour-version inside the method?
Tried with -
#GetMapping(value = "/score", params ="behaviour-version=2")
public UserScoreResV2 getUserScoreV2(#RequestHeader("api-key") String apiKey,
#RequestHeader("jwt") String jwt,
#RequestParam(name = "behaviour-version", required = false) String behaviourVersion,
#RequestParam(name = "date", defaultValue = "2022-07-15") String dateStr) {
....
}
but, it is not working.
Can not modify method 1 (getUserScore) because a version is released in production with that.
try this
#GetMapping(value = "/score", params ="behaviour-version=2")
public UserScoreResV2 getUserScoreV2(#RequestHeader("api-key") String apiKey,
#RequestHeader("jwt") String jwt,
#RequestParam(name = "date", defaultValue = "2022-07-15") String dateStr,
ServletRequest request) {
String behaviorVersion = request.getParameter("behaviour-version");
}
warning
As Deinum mentioned, behavior-version should be 2.
Otherwise, you can't send request. The server will return 400 error
You can do this using handler interceptor. What you have to do is when application recieve a request for /score endpoint with behaviour_version header or param you have to redirect that to the another endpoint through preHandler (ex: /score/v2 ).
Then caller can send request for same endpoint with additional header/param. Redirecting according to header do by springboot interceptor.
Ex handler inteceptor:
public class ScoreInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if(request.getParameter(behaviour_v)=="2"){
response.redirect('/score/v1');
return false;
}
return true;
}
}

Spring throwing 403 exception on POST request but POSTMAN request working

I am trying to POST some data to rest api, When I send the request to API using SPRING REST I get the 403 exception.
I have tried adding user-agent header as suggested by other answers but nothing has worked for me so far. I also checked that access key when using POSTMAN and when calling the service is same. Any advice would be helpful;
The wrapper class to create the body of POST request
public class ApiRequest implements Serializable {
private static final long serialVersionUID = 3729607216939594972L;
#JsonProperty("id")
List<Integer> id;
#JsonProperty("sdate")
String sdate;
#JsonProperty("edate")
String edate;
#JsonProperty("fields")
List<String> fields;
public ApiRequest(List<Integer> id, String sdate, String edate, List<String> fields){
this.id=id;
this.sdate=sdate;
this.edate=edate;
this.fields=fields;
}
public void setEdate(String edate) {
this.edate = edate;
}
public void setSdate(String sdate){
this.sdate=sdate;
}
public void setFields(List<String> fields) {
this.fields = fields;
}
public void setId(List<Integer> id) {
this.id = id;
}
public String getEdate() {
return edate;
}
public String getSdate() {
return sdate;
}
public List<String> getFields() {
return fields;
}
public List<Integer> getId() {
return id;
}
#Override
public String toString() {
return "ApiRequest{" +
"id=" + id +
", sdate=" + sdate +
", edate=" + edate +
", fields=" + fields+
'}';
}
}
Code to call the api
private HttpHeaders getRequestHeaders() {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(Arrays.asList(MediaType.ALL));
requestHeaders.set("user-agent","Some User Agent);
requestHeaders.set("access_token", "ACCESS_TOKEN");
return requestHeaders;
}
ApiRequest request=new ApiRequest(Arrays.asList(10),DateUtil.today().toString(),DateUtil.today().plusDays(10).toString(),Arrays.asList("ALL"));
String response=post("RANDOM_URL",null,null,request,getRequestHeaders(),String.class,"");
Post super method:
public <T> T post(String baseUrl, String url, String query, Object body, HttpHeaders requestHeaders, Class<T> responseClassType, String logTag) {
// In this method body is converted to Json String and called the restExchange
If you are sure that with Postman you are getting correct results then you can enable debug logs for the underlying httpclient ( if apache http client is the underlying http library) by setting logging.level.org.apache.http=DEBUG. This will print all the request details like url, headers etc by which you can compare with what you are sending with Postman. If the client library is something different then you may need to write an interceptor to capture all the request details as explained here.

Spring redirect from ErrorController

I have a number of generic error pages which are used by multiple applications other than the one I have control of. I would like to configure the Spring Boot error controller to do a redirect to one of these pages. Unfortunately it's not working.
Eg.
#Controller
public class MyCustomErrorController implements ErrorController {
#GetMapping(value = "/error")
public String handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (status != null) {
Integer statusCode = Integer.valueOf(status.toString());
if (statusCode == HttpStatus.NOT_FOUND.value()) {
return "redirect:https://www.example.com/error-404";
}
}
return "redirect:https://www.example.com/error-500";
}
#Override
public String getErrorPath() {
return "/error";
}
}
If for example I purposefully mistype a URL I can see the response has the Location header with the 404 URL I am expecting but the browser doesn't actually redirect. Any ideas if it's possible to do a redirect from within a custom ErrorController?
Could this be because I'm trying to test this from localhost, and Strict-Transport-Security is ignoring the response Location header value (which is on a FQDN)?
How about adding HttpServletResponse to the method param and use it for redirection?
HttpServletResponse response;
response.sendRedirect("https://www.example.com/error-404");
Reference HERE
Add the following properties in application.proerties file
server.error.whitelabel.enabled=false
try this.
#Controller
public class MyCustomErrorController implements ErrorController {
#GetMapping(value = "/error")
public String handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (status != null) {
Integer statusCode = Integer.valueOf(status.toString());
if (statusCode == HttpStatus.NOT_FOUND.value()) {
return "redirect:/error-404"; //remove your https://www.example.com
}
}
return "redirect:/error-500";
}
#Override
public String getErrorPath() {
return "/error";
}
}
** EDIT **
change the url mapping and try again:
error-404 -> error/404
error-500 -> error/500
#Controller
public class MyCustomErrorController implements ErrorController {
#GetMapping(value = "/error")
public String handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (status != null) {
Integer statusCode = Integer.valueOf(status.toString());
if (statusCode == HttpStatus.NOT_FOUND.value()) {
return "redirect:/error/404"; //remove your https://www.example.com
}
}
return "redirect:/error/500";
}
#Override
public String getErrorPath() {
return "/error";
}
}
error/404
#GetMapping("/error/404")
error/500
#GetMapping("/error/500")

WebApi: method to return a simple string

One of my methods need to return just a simple string of text. What should be the return type of the method? Do I still declare it in a subclass of ApiController?
I tried the following but it does not work:
public class TestController : ApiController
{
public string Announcements()
{
return "Testing abc";
}
}
By default, Web API will send the string as a JSON. However, you can manually force it to return just the text itself and accompany it with the appropriate content type:
public class TestController : ApiController
{
public HttpResponseMessage Announcements()
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent("Testing abc");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
return response;
}
}

Resources