So in my Spring controller, i have this route
#RequestMapping(value = "myroute", method = POST)
public String myRoute(HttpServletRequest) {
...
}
We use MockMvcBuilder to mock the POST calls.
MockHttpServletRequestBuilder post = post(myRouteUrl);
mockMvc.perform(post).andExpect(status().isOK());
Now if i just change post to get, the status back is still 200.
So how to verify GET method is failing ?
Using Java 1.8.
Thanks !
I got a HTTP error 405 when I tried the following. Is there something else missing from the example shown?
This is the controller class I used.
package demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
#RestController
public class MyController {
#RequestMapping(value = "/myroute", method = GET)
public String myRoute(HttpServletRequest request) {
System.out.println("HERE");
return "good";
}
}
This is the test class I used.
package demo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#ExtendWith(MockitoExtension.class)
#WebMvcTest(MyController.class)
class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
void myRoute() throws Exception {
MockHttpServletRequestBuilder post = post("/myroute");
mockMvc.perform(post).andExpect(status().isOk());
}
}
Error Message:
Error message = Request method 'POST' not supported
Headers = [Allow:"GET"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Status expected:<200> but was:<405>
Expected :200
Actual :405
Related
I'm new to Java and react web development and I'm having an issue with my postBody method. After sending a post request, the console prints the data posted from my frontend correctly, but it shows a whitelabel error page that says (type=Not Found, status=404) in localhost:8080/api and (type=Method Not Allowed, status=405) in localhost:8080/api/data. Below is the HelloController code.
package com.java.java.practice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;
import org.springframework.web.cors.CorsConfiguration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
#RestController
#RequestMapping("/api")
public class HelloController {
//this performes a post and get request
#CrossOrigin(origins = "http://localhost:3000/api")
#PostMapping(value="/n", consumes = MediaType.APPLICATION_JSON_VALUE)
public String postBody(#RequestBody String fullName) {
System.out.println(fullName);
return "Hello " + fullName; //returns response
}
}
Below is the main application
package com.java.java.practice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan(basePackages="com.java.java.practice")
public class PracticeApplication {
public static void main(String[] args) {
SpringApplication.run(PracticeApplication.class, args);
}
}
The weird thing is, when I replace my HelloController code with the one posted underneath, the whitelabel page goes away and shows text on the screen.
package com.java.java.practice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;
import org.springframework.web.cors.CorsConfiguration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
#RestController
public class HelloController {
//this performes a post and get request
#CrossOrigin(origins = "http://localhost:3000/api")
#RequestMapping("/api")
public String postBody() {
return "Hello"; //returns response
}
}
Any help would be much appreciated.
I can see a few issues as below,
When you try to call via a web browser it's always calling as HTTP GET. But in your RestController, there is no GET method. It only has a POST method. Try to use Postman or CURL to call post method instead of GET.
Your URL is wrong. Since you appending /n for the PostMapping annotation it should be (http://localhost:3000/api/n)
Only you want fullName as request body try to use PathVariable instead. No point to use RequestBody only for 1 parameter. Sample code as below.
#PostMapping(value="/{fullName}", consumes = MediaType.APPLICATION_JSON_VALUE)
public String postBody(#PathVariable String fullName) {
System.out.println(fullName);
return "Hello " + fullName; //returns response
}
I have a java bean which has both multipart and String data. I am trying to pass it in a rest client call which takes this java bean input and processes it.
Below are my model class, controller and rest client.
On making a call from my rest client , I am getting this exception.
Exception in thread "main" org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [com.techidiocy.models.NHPdfMergeRequest] and content type [multipart/form-data]
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:810)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:594)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:384)
Model Class
import org.springframework.web.multipart.MultipartFile;
public class Candidate {
private String firstName;
private String lastName;
private MultipartFile resume;
//getters and setters
}
Controller Class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
#RestController
public class CandidateController {
#Autowired
private CandidateService candidateService;
#RequestMapping(method=RequestMethod.POST, path="/add")
public void add(#RequestBody Candidate request) {
// do some processing
String firstName = request.getFirstName();
String lastName = request.getLastName();
MultipartFile resume = request.getResume();
candidateService.add(firstName, lastName, resume);
}
}
Rest Client
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.client.RestTemplate;
public class CandidateClient {
public static void main(String[] args) throws IOException {
String serverURL = "http://localhost:8080/add";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
Candidate candidate = new Candidate();
candidate.setFirstName("John");
candidate.setLastName("Doe");
candidate.setResume(new MockMultipartFile("tmp.pdf", FileUtils.readFileToByteArray(new File("/home/john/resume/john.pdf"))));
HttpEntity<Candidate> httpEntity = new HttpEntity<Candidate>(candidate, headers);
RestTemplate client = new RestTemplate();
client.postForEntity(serverURL, httpEntity, Resource.class);
}
}
Note: I had also tried to set the header content type as json in rest client and then I am getting all the values as Null in the controller. headers.setContentType(MediaType.APPLICATION_JSON);
I had also searched over the internet for this kind of scenario but I am unable to find a solution for this.
I had also tried to pass all the parameters separately (not as part of java bean) then I am able to make it work.
I have a rest controller, which has simple CRUD operations. I am trying to write integration test.
Below is my RestController:
package com.gasx.corex.scheduler.controller;
import java.awt.*;
import java.util.List;
import com.gasx.corex.scheduler.service.SchedulerJobServiceI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.gasx.corex.ext.scheduler.domain.SchedulerJob;
import com.gasx.corex.scheduler.service.SchedulerJobService;
#RestController
#RequestMapping("/gasx/restscd")
public class SchedulerJobController {
#Autowired
private SchedulerJobServiceI schedulerJobService;
#RequestMapping(method = RequestMethod.GET , path="/getschedulerjobs" , produces= MediaType.APPLICATION_JSON_VALUE)
public List<SchedulerJob> getAllSchedulerJobs() {
return schedulerJobService.getAllSchedulerJobs();
}
#RequestMapping(method = RequestMethod.POST, value = "/addschedulerjob")
public void addSchedulerJob(#RequestBody SchedulerJob schedulerJob) {
schedulerJobService.addSchedulerJob(schedulerJob);
}
#RequestMapping(method = RequestMethod.POST, value = "/updateschedulerjob")
public void updateSchedulerJob(#RequestBody SchedulerJob schedulerJob) {
schedulerJobService.updateSchedulerJob(schedulerJob);
}
#RequestMapping(method = RequestMethod.POST, value = "/deleteschedulerjob")
public void deleteSchedulerJob(#RequestBody SchedulerJob schedulerJob) {
schedulerJobService.deleteSchedulerJob(schedulerJob);
}
}
I have written Integration test for all of the endpoints in RestController
Integration test class :-
package com.gasx.corex.ext.scheduler.integrationtest.domain;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gasx.corex.base.configuration.CoreConfiguration;
import com.gasx.corex.ext.scheduler.domain.SchedulerJob;
import com.gasx.corex.ext.scheduler.domain.utils.SchedulerJobType;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import sun.security.krb5.internal.Ticket;
import org.springframework.http.HttpMethod;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import java.io.IOException;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT , properties = {
"management.server.port=0", "management.context-path=/admin" ,"security.basic.enabled=false"} )
#EnableAutoConfiguration
#ContextConfiguration( classes = {CoreConfiguration.class } )
#AutoConfigureMockMvc
public class SchedulerJobTestInt {
#LocalServerPort
private int port ;
#Autowired
private TestRestTemplate testRestTemplate;
#Autowired
WebApplicationContext context;
#Autowired
private MockMvc mockMvc;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
#Test
public void getAllSchedulerJobsIntTest() throws Exception {
ResponseEntity<String> response = testRestTemplate.getForEntity("http://localhost:" + port +"/gasx/restscd/getschedulerjobs", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode responseJson = objectMapper.readTree(response.getBody());
assertThat(responseJson.isMissingNode()).isFalse();
assertThat(responseJson.toString()).isEqualTo("[]");
}
#Test
public void addSchedulerJobIntTest() throws Exception{
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName("ALB Cleanup");
schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
schedulerJob.setType(SchedulerJobType.REST);
schedulerJob.setActive(true);
schedulerJob.setStartMissedRun(false);
schedulerJob.setCategory("SYSTEM");
schedulerJob.setCronExpression(null);
schedulerJob.setScheme("testScheme");
schedulerJob.setIdRegion(1);
schedulerJob.setAlbEndpoint("testAlbEndPoint");
schedulerJob.setAlbPayload("SCHED_ALB");
schedulerJob.setAlbPrio(1);
schedulerJob.setAlbJobUser("MKRAUS");
schedulerJob.setScriptParams("testScriptParams");
schedulerJob.setShellScriptParams("clear_tmp 15");
schedulerJob.setSoapEndpointAlias("");
schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
schedulerJob.setSoapExportPath("testExportPath");
schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
schedulerJob.setSoapAction("urn:readPartnersById");
schedulerJob.setRestEndpointAlias("testEndpointAlias");
schedulerJob.setRestUrl("testUrl");
schedulerJob.setRestEntityContent("");
schedulerJob.setRestExportPath("testRestExportPath");
schedulerJob.setHookScriptName("testHookScriptName");
schedulerJob.setMinutes("");
schedulerJob.setHours("");
String plainCredentials="gasx:gasx!";
String base64Credentials = Base64.getEncoder().encodeToString(plainCredentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
headers.add("Accept" , "application/json");
HttpEntity<String> entity = new HttpEntity<String>(asJsonString(schedulerJob), headers);
// ResponseEntity<Void> response = testRestTemplate.postForEntity("http://localhost:"+port +"/gasx/restscd/addschedulerjob", entity,Void.class);
ResponseEntity<Void> response = testRestTemplate.postForEntity("http://localhost:" + port +"/gasx/restscd/addschedulerjob", asJsonString(schedulerJob),Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
#Test
public void updateSchedulerJobTest(){
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName("ALB Cleanup");
schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
schedulerJob.setType(SchedulerJobType.REST);
schedulerJob.setActive(true);
schedulerJob.setStartMissedRun(false);
schedulerJob.setCategory("SYSTEM");
schedulerJob.setCronExpression(null);
schedulerJob.setScheme("testScheme");
schedulerJob.setIdRegion(1);
schedulerJob.setAlbEndpoint("testAlbEndPoint");
schedulerJob.setAlbPayload("SCHED_ALB");
schedulerJob.setAlbPrio(1);
schedulerJob.setAlbJobUser("MKRAUS");
schedulerJob.setScriptParams("testScriptParams");
schedulerJob.setShellScriptParams("clear_tmp 15");
schedulerJob.setSoapEndpointAlias("");
schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
schedulerJob.setSoapExportPath("testExportPath");
schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
schedulerJob.setSoapAction("urn:readPartnersById");
schedulerJob.setRestEndpointAlias("testEndpointAlias");
schedulerJob.setRestUrl("testUrl");
schedulerJob.setRestEntityContent("");
schedulerJob.setRestExportPath("testRestExportPath");
schedulerJob.setHookScriptName("testHookScriptName");
schedulerJob.setMinutes("");
schedulerJob.setHours("");
ResponseEntity<Void> response = testRestTemplate.withBasicAuth("gasx" ,"gasx!").postForEntity("http://localhost:" + port +"/gasx/restscd/updateschedulerjob", schedulerJob,Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
#Test
public void deleteSchedulerJob(){
SchedulerJob schedulerJob = new SchedulerJob();
schedulerJob.setName("ALB Cleanup");
schedulerJob.setDescription("Cleanup of alb jobs. Please do not deactivate!");
schedulerJob.setType(SchedulerJobType.REST);
schedulerJob.setActive(true);
schedulerJob.setStartMissedRun(false);
schedulerJob.setCategory("SYSTEM");
schedulerJob.setCronExpression(null);
schedulerJob.setScheme("testScheme");
schedulerJob.setIdRegion(1);
schedulerJob.setAlbEndpoint("testAlbEndPoint");
schedulerJob.setAlbPayload("SCHED_ALB");
schedulerJob.setAlbPrio(1);
schedulerJob.setAlbJobUser("MKRAUS");
schedulerJob.setScriptParams("testScriptParams");
schedulerJob.setShellScriptParams("clear_tmp 15");
schedulerJob.setSoapEndpointAlias("");
schedulerJob.setSoapImportPath("CORE/CORE2003/imp/price");
schedulerJob.setSoapExportPath("testExportPath");
schedulerJob.setSoapPayload("<api:readPartnersByIdRequest>");
schedulerJob.setSoapAction("urn:readPartnersById");
schedulerJob.setRestEndpointAlias("testEndpointAlias");
schedulerJob.setRestUrl("testUrl");
schedulerJob.setRestEntityContent("");
schedulerJob.setRestExportPath("testRestExportPath");
schedulerJob.setHookScriptName("testHookScriptName");
schedulerJob.setMinutes("");
schedulerJob.setHours("");
ResponseEntity<Void> response = testRestTemplate.withBasicAuth("gasx" ,"gasx!").postForEntity("http://localhost:" + port +"/gasx/restscd/deleteschedulerjob", schedulerJob,Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
My problems:
1.)Wheneever I put breakpoint in Rest Controller, it doesnt' stop there, actually it is not getting invoked.
2.)When I run the test for GET it returns sign-in html page from response.getBody()
3.)When I run the test for POST it returns status 401 unauthorized
tried numerious possible solutions on google
even disabled spring security by commenting the the configuration still it doesn't work.
I can call the same Rest Controller from my Unit test and can stop the breakpoints.
My security configurations:-
package com.gasx.corex.scheduler.server;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import com.gasx.corex.ext.user.domain.DefaultRoles;
#Configuration
#EnableWebSecurity
#Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/gasx/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
.antMatchers("/webjars/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
.antMatchers("/monitor/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ACTUATOR.getName())
// dev urls
.antMatchers("/h2-console/**").hasAuthority(DefaultRoles.ROOT.getName())
.antMatchers("/swagger*/**","/v2/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName())
.anyRequest().denyAll();
// #formatter:on
httpSecurity.csrf().disable();
httpSecurity.headers().frameOptions().disable();
}
}
Tried one more thing, added below class to my package :-
package com.gasx.corex.ext.scheduler.integrationtest.domain;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
public class AllowAnonymousWebAccess extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity web) throws Exception {
web.antMatcher("**/*").anonymous();
}
}
and now it gives 404.
I don't know anything about this project's SecurityConfiguration (you should provide some more information about it), but I think that you should provide some authorization data (Like a JWT in the Authorization header, or so)
Could you give me some more information about the SecurityConfig? (look for org.springframework.security.config.something.something... imports )
EDIT
I took a look at your code, and actually this part
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.httpBasic().and()
.authorizeRequests()
.antMatchers("/gasx/**").hasAnyAuthority(DefaultRoles.ROOT.getName(), DefaultRoles.ADMIN.getName(), DefaultRoles.ACTUATOR.getName())
is protecting your API with an httpBasic type authorization. You shold provide the credentials in the header to test your application.
I am creating a Rest controller in JAVA . When I run the application locally , I am able to do POST operations. Then I create a JAR and then deploy it on a server . Plz note that I am using Netflix Eureka for service discovery and zuul as API gateway . The application starts running fine on server and it is registered in Eureka server as well . But when I use POST service , its giving me error : 405 Method Post not supported .
Controller class
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.bp.budgetpulse.domain.FeedBackEmployeeDetails;
import com.bp.budgetpulse.service.FeedBackService;
#RestController
#RequestMapping(value = "/api/v1")
public class FeedBackController {
#SuppressWarnings("unused")
private final Logger logger = LoggerFactory.getLogger(FeedBackService.class);
#Autowired
private FeedBackService feedbackService;
/**
* This method to save the feedback details
*
* #param feedbackDetails
* #param userName
* #return response
*/
#RequestMapping(value = "/saveEmployeeFeedbackDetails", method = RequestMethod.POST)
public String saveEmployeeFeedbackDetails(#RequestBody FeedBackEmployeeDetails empFeedbackDetails) {
return feedbackService.saveEmployeeFeedbackDetails(empFeedbackDetails);
}
/**
*
* this method to get the feedback details
*
* #return feedback details
*/
#RequestMapping(value = "/getFeedBackDetails/{email}", method = RequestMethod.GET)
public FeedBackEmployeeDetails getFeedBackDetails(#PathVariable String email) {
return feedbackService.getFeedBackDetails(email);
}
}
POST method is supported in Netflix Eureka and ZUUL. Netflix Eureka and ZUUL do not impose any restriction on the API Methods. Here is a sample controller code that I have written that works without any issues in a Netflix Eureka and ZUUL environment:
import com.aj.gradingservice.model.Grade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#RestController
#RequestMapping("/")
public class GradeController {
private static final Logger logger = LoggerFactory.getLogger(GradeController.class);
#RequestMapping(value = "ping", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> ping() {
Map<String, String> response = new HashMap<>();
response.put("message", "pong");
return new ResponseEntity<>(response, HttpStatus.OK);
}
#RequestMapping(value = "grades", method = RequestMethod.GET)
public ResponseEntity<List<Grade>> getGrades() {
logger.info("In GradeController.getGrades(), fetching list of grades");
List<Grade> grades = new ArrayList<>();
grades.add(new Grade(1, "P001", "A+"));
grades.add(new Grade(2, "C001", "A"));
grades.add(new Grade(3, "M001", "B+"));
return new ResponseEntity<>(grades, HttpStatus.OK);
}
#RequestMapping(value = "grade", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Grade> createGrade(#RequestBody Grade grade) {
logger.info("Request received is: " + grade );
Grade gradeCreated = new Grade(grade.getId(),grade.getStudentId(),grade.getGrade());
return new ResponseEntity<>(gradeCreated, HttpStatus.OK);
}
}
I have written a blog post with the detailed explanation of setting up a Netflix Eureka and Zuul environment and there is end to end working code in GitHub. Please check: http://softwaredevelopercentral.blogspot.com/2018/02/spring-cloud-eureka-and-zuul.html
Background: Search form in a webapp, with an auto-complete/suggestion. Using jQuery's autocomplete, suggestions are shown after typing a few characters. These suggesitons are retrieved as JSON data from one of the webapp's controllers.
Issue: I am testing the application via the HtmlUnit Integration of Spring Test, which works fine for Text/Html Pages, but for the JSON responses here, the setup seems to fail (see error below).
Manually testing (the actual webapp) via Browser works and fetching JSON from "real" pages works as well ( see "json()" test) -> Should testing JSON responses work via HtmlUnit / Spring Test setup and if yes, what am I doing wrong?
Update (2017-06-21):
Using
#ResponseBody String
and building the JSON "manually" (not letting Spring automagically doing it) works; not really what I wanted, but at least I can properly test it this way ...
Test:
package my.project;
import com.gargoylesoftware.htmlunit.*;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.*;
import org.springframework.test.*;
import org.springframework.web.context.support.GenericWebApplicationContext;
import javax.servlet.ServletException;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {TestWebAppConfig.class,
// avoid context caching
MyControllerIT.class})
#WebAppConfiguration
public class MyControllerIT {
protected static final String SERVER_URL = "http://localhost";
protected WebClient webClient;
protected MockHttpServletRequest request;
protected MockHttpServletResponse response;
#Autowired
protected GenericWebApplicationContext webApplicationContext;
#Before
public void setUp() throws Exception {
this.request = new MockHttpServletRequest();
this.request.setServerName("Gondor.Osgiliath");
this.response = new MockHttpServletResponse();
this.webClient = this.initClient();
}
protected final WebClient initClient() throws ServletException {
DefaultMockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(this.webApplicationContext);
MockMvc mockMvc = mockMvcBuilder.build();
WebClient webClient = new WebClient();
webClient.setWebConnection(new MockMvcWebConnection(mockMvc));
return webClient;
}
// https://stackoverflow.com/questions/2932857/html-handling-a-json-response
#Test
public void json() throws Exception {
webClient = new WebClient(BrowserVersion.INTERNET_EXPLORER, "some.proxy", 7890);
Page page = webClient.getPage("https://stackoverflow.com/users/flair/97901.json");
WebResponse webResponse = page.getWebResponse();
String contentType = webResponse.getContentType();
String contentAsString = webResponse.getContentAsString();
}
#Test
public void suggestShouldReturnJSON() throws Exception {
Page page = webClient.getPage(SERVER_URL + MyController.SUGGEST_URL + "?term=asdf");
WebResponse webResponse = page.getWebResponse();
String contentType = webResponse.getContentType();
String contentAsString = webResponse.getContentAsString();
}
#Test
public void suggestShouldReturnJSONViaMockMvc() throws Exception {
MockMvc springMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
ResultActions resultActions = springMvc.perform(MockMvcRequestBuilders
.get(MyController.SUGGEST_URL + "?term=asdf")
.accept(MediaType.APPLICATION_JSON_VALUE));
resultActions.andDo(MockMvcResultHandlers.print());
}
}
Controller:
package my.project;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.List;
#Controller
public class MyController {
public static final String SUGGEST_URL = "/suggest";
//http://api.jqueryui.com/autocomplete/#option-source
#RequestMapping(value = {SUGGEST_URL,}, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
List<Suggestion> suggest(#RequestParam(name = "term") String term) {
return Arrays.asList(new Suggestion("label1", "value1"), new Suggestion("label2", "value2"));
}
}
Config (Thymeleaf omitted for the moment):
package my.project;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#EnableWebMvc
#ComponentScan(basePackages = {"my.project.*",})
#Configuration
#Import(ThymeleafConfig.class)
abstract class TestWebAppConfig extends WebMvcConfigurerAdapter {
}
Error:
com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException: 406 Not Acceptable for http://localhost/suggest?term=asdf
at com.gargoylesoftware.htmlunit.WebClient.throwFailingHttpStatusCodeExceptionIfNecessary(WebClient.java:571)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:396)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:304)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:451)
at com.gargoylesoftware.htmlunit.WebClient.getPage(WebClient.java:436)
at my.project.MyControllerIt.suggestShouldReturnJSON(MyControllerIt.java:
...