Spring Boot Tries to Access A Post Request URL but shows GET not supported - spring

I just started to learn Spring Boot today, and I wanted to create a GET/POST request for my Spring Boot Project. When I tried to access the URL that has the post request it shows 405 error saying that "Request method 'GET' not supported".
I think it is something wrong about my code for the POST request, but I don't know where I did wrong. I tried to search for the a tutorial that teaches how to write a proper GET/POST request, so I couldn't find anything good.
If you guys have any good website that teaches basic HTTP requests in Spring Boot, that will be great. I tried to find answers at StackOverflow, but I didn't find anything answers.
The Spring Boot project I have been using is the one from the official Spring.io website: https://spring.io/guides/gs/rest-service/
I wanted to call the POST request for my project so I have a better understanding of the HTTP.
Here is the source code for the controller:
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.*;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
#RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
// GET Request
#RequestMapping(value="/greeting", method = GET)
public Greeting greeting(#RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(), name);
}
#RequestMapping(value = "/testpost", method = RequestMethod.POST)
public String testpost() {
return "ok";
}
}
Here is the source code for the Application:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And here is the source code for the Greeting Object
package hello;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
I can get the GET request working by using the "/greeting" URL.
I tried to access the "/testpost" url but it shows 405 error that the GET method is not supported.
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported

If you try to open the http://localhost:8080/testpost by directly opening in browser, it won't work because opening in browser makes a GET request.
I am not sure how you are trying to do a post request, I tried to do the same post request from postman and able to get the response. Below is the screenshot.

It looks like you are trying to make post request directly from web browser which will not work.
When you hit a URL directly from web browser address bar, it is considered as GET request. Since in your case, there is no GET API as /testpost , it is giving error.
Try to use rest client such as Postman or curl command to make post request.
I tried your post end-point with postman and it is working properly. PFA snapshot for your reference.
Hope this helps.

From where you are trying POST request. If from browser windows you calling POST call, then it will not work, browser will send only GET request. Have you tried from postman or from UI side. It will work.

Related

Spring Web - 405 method not allowed

I recently tried to program a simple api in spring.
When I try it with postman, the only two working endpoints are the fetchAllMovie and the createMovie. The others (with request parameter) give a response:
{
"timestamp": "2021-11-30T14:38:34.396+00:00",
"status": 405,
"error": "Method Not Allowed",
"path": "/api/movies"
}
Here's a snippet:
#RestController
#RequestMapping("/api/movies")
public class MovieController {
#Autowired
private MovieService movieService;
#Autowired
private MovieRepository movieRepository;
#Autowired
private MovieMapper movieMapper;
#GetMapping
public List<Movie> fetchAllMovie() {
return movieService.getAllMovie();
}
#PostMapping
public MovieDto createMovie(#RequestBody MovieCreationDto movieCreationDto) {
Movie movie = movieMapper.creationDtoToModel(movieCreationDto);
return movieMapper.modelToDto(movieRepository.save(movie));
}
#GetMapping("/{movieId}")
public MovieDto fetchMovieById(#PathVariable("movieId") String movieId) throws MovieNotFoundException {
Movie movie = movieRepository.findById(movieId).orElseThrow(MovieNotFoundException::new);
return movieMapper.modelToDto(movie);
}
}
So if I send a GET request like http://localhost:8080/api/movies?movieId=619fa9d9b0c30252474b9a01 I get the error, but if I send a GET or POST request like http://localhost:8080/api/movies i can get all of the data from the data base or I can POST in it. (Of course with the proper request body)
Note it: Not only the GET req not working. Anything with request parameter gives me this error.
The #PathVariable is used to send parameter in path, like this: http://localhost:8080/api/movies/619fa9d9b0c30252474b9a01
If you want to send it using URL you specified, you need to use annotation #RequestParam
If you are using the #PathVariable as the input parameter, then you should call the endpoint in the following way:
http://localhost:8080/api/movies/619fa9d9b0c30252474b9a01
If you would like to use the #RequestParameter then call the api like this:
http://localhost:8080/api/movies?movieId=619fa9d9b0c30252474b9a01
Quick summary:
https://www.baeldung.com/spring-requestparam-vs-pathvariable

Cannot properly test ErrorController Spring Boot

due to this tutorial - https://www.baeldung.com/spring-boot-custom-error-page I wanted to customize my error page ie. when someone go to www.myweb.com/blablablalb3 I want to return page with text "wrong url request".
All works fine:
#Controller
public class ApiServerErrorController implements ErrorController {
#Override
public String getErrorPath() {
return "error";
}
#RequestMapping("/error")
public String handleError() {
return "forward:/error-page.html";
}
}
But I dont know how to test it:
#Test
public void makeRandomRequest__shouldReturnErrorPage() throws Exception {
this.mockMvc.perform(get(RANDOM_URL))
.andDo(print());
}
print() returns:
MockHttpServletResponse:
Status = 404
Error message = null
Headers = {X-Application-Context=[application:integration:-1]}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
So I cant created something like this:
.andExpect(forwardedUrl("error-page"));
because it fails, but on manual tests error-page is returned.
Testing of a custom ErrorController with MockMvc is unfortunately not supported.
For a detailed explanation, see the official recommendation from the Spring Boot team (source).
To be sure that any error handling is working fully, it's necessary to
involve the servlet container in that testing as it's responsible for
error page registration etc. Even if MockMvc itself or a Boot
enhancement to MockMvc allowed forwarding to an error page, you'd be
testing the testing infrastructure not the real-world scenario that
you're actually interested in.
Our recommendation for tests that want to be sure that error handling
is working correctly, is to use an embedded container and test with
WebTestClient, RestAssured, or TestRestTemplate.
My suggestion is to use #ControllerAdvice
In this way you can work around the problem and you can continue to use MockMvc with the big advantage that you are not required to have a running server.
Of course to test explicitly the error page management you need a running server. My suggestion is mainly for those who implemented ErrorController but still want to use MockMvc for unit testing.
#ControllerAdvice
public class MyControllerAdvice {
#ExceptionHandler(FileSizeLimitExceededException.class)
public ResponseEntity<Throwable> handleFileException(HttpServletRequest request, FileSizeLimitExceededException ex) {
return new ResponseEntity<>(ex, HttpStatus.PAYLOAD_TOO_LARGE);
}
#ExceptionHandler(Throwable.class)
public ResponseEntity<Throwable> handleUnexpected(HttpServletRequest request, Throwable throwable) {
return new ResponseEntity<>(throwable, HttpStatus.INTERNAL_SERVER_ERROR);
}
}

Implement Best-Practice Error Message in Spring REST Controller

I am writing a server-side REST application for a mobile app. I have been trying to setup an exception handler which follows the explanation here, where instead of showing some HTTP error page, the client receives a JSON object similar to this one:
{
"status": 404,
"code": 40483,
"message": "Oops! It looks like that file does not exist.",
"developerMessage": "File resource for path /uploads/foobar.txt does not exist. Please wait 10 minutes until the upload batch completes before checking again.",
"moreInfo": "http://www.mycompany.com/errors/40483"
}
I have modeled my exception on those detailed in the guide, and they seem to be working well (the custom errors are being shown in the console). But I got stuck at this point, because I don't know where I'm supposed to put the bean configuration.
Given that I have all my exception handlers, resolvers, etc., I thought I'd try go around it differently. At this point I would still get Spring's Whitelabel error page when I entered an invalid HTTP request, but this time with my custom error messages from my exceptions. So I figured if I tried to implement my own ErrorHandler as explained here, I might be able to construct the JSON objects using Gson or something, instead of the way the previous article went about it.
I tried to get a bare minimum ErrorHandler working:
package com.myapp.controllers;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
#RestController
public class ErrorMessageController implements ErrorController {
private static final String ERROR_PATH = "/error";
#Override
public String getErrorPath(){
return ERROR_PATH;
}
#RequestMapping(value = ERROR_PATH)
public String renderErrorPage(HttpServletRequest request){
String errorPage = (String) request.getAttribute("javax.servlet.error.status_code");
return errorPage;
}
}
So I expected to get something like a solitary 404 appearing on the webpage. But instead I'm getting a Tomcat error page:
Why is this? I'd appreciate any help.
This happens because request.getAttribute("javax.servlet.error.status_code") should be an Integer and you're casting it as a String. This causes an error during the error handling, which pops up the default Tomcat error handler.
If you cast it as an int, it will work:
#RequestMapping(value = ERROR_PATH)
public int renderErrorPage(HttpServletRequest request){
int errorPage = (int) request.getAttribute("javax.servlet.error.status_code");
return errorPage;
}
Alternatively, if you just want to return certain JSON structure, you could use #ExceptionHandler methods in stead of implementing an ErrorController.
For example, let's say you have the following controller:
#GetMapping
public String getFoo() throws FileNotFoundException {
throw new FileNotFoundException("File resource for path /uploads/foobar.txt does not exist");
}
If you want to handle all FileNotFoundExceptions in a particular way, you could write a method with the #ExceptionHandler annotation:
#ExceptionHandler(FileNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse notFound(FileNotFoundException ex) {
return new ErrorResponse(HttpStatus.NOT_FOUND.value(), 40483, "Oops! It looks like that file does not exist.", ex.getMessage(), "http://www.mycompany.com/errors/40483");
}
In this case, ErrorResponse is a POJO containing the fields you want. If you want to re-use this for all your controllers, you can put this in a #ControllerAdvice.

Error 404 on PUT request while having a GET

Got a small problem on my rest server. It's based on spring web framework.
Here's the code that poses me problems :
#RestController
#RequestMapping("users")
public class usersWS {
//some other functions
//works
#RequestMapping(
value="/{iduser}/functions/",
method=RequestMethod.GET,
produces={"application/json"})
public ResponseEntity<String> getUserFunctions(#PathVariable("iduser") String iduser){
//do stuff
return stuff;
}
//Don't works
#RequestMapping(
value="/{iduser}/functions/"
method=RequestMethod.PUT,
consumes={"application/json"})
public ResponseEntity<String> addUserFunctions(#RequestBody String json, #PathVariable("iduser") String iduser){
//do stuff
return stuff;
}
}
Server is launched by :
#SpringBootApplication()
#ImportResource("classpath*:**/jdbc-context.xml")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
To call this server, I use the HTML handler found here : Spring HTTP Client
When I call the get verb, everything is working fine. I get the iduser, get the data I want, no problem.
When I call the put verb... I have an error 404. I checked, the url (http://localhost:8080/users/xxx/functions/) are exactly the same, I do send the body.
I would understand to get a 405 error, but I really don't understand how I can have a 404. If the mapping was wrong, the server should at least see that there is a function on the get verb and throw me a 405.
I have other functions using the PUT/POST that are working but they don't have a #PathVariable. Is it possible to mix #RequestBody and #PathVariable ?
Any help is gladly welcome.

How can i ignore some path of vaadin ? /HEARTBEAT /UIDL /VAADIN

I am using a vaadin application with the dashboardemo example
My class does not use a VaadinSevlet but, a VaadinCDIServlet
My webServlet 3.0 I have it so
#WebServlet (asyncSupported = false, urlPatterns = {"/*"},
I will not serve any static content otherwise I would write another
urlpattern as well /VAADIN/*
The problem is that when I visit the path as
/HEARTBEAT/?v-uid=0
/HEARTBEAT
/UIDL/?v-uiId=2
/VAADIN/
/VAADIN/themes/valo/fonts
I get different errors, as I can show some errorView or redirect users to a main view,
The demo dashboard actually redirects some incorrect url or fragments !#blalbla, redirect to
https://domain/myapp/#!dashboard
but with these path does not it, I have reviewed many applications and it happens just the same, whether we are demos or not.please some help?
Update
The solution I recommend for this in case of handling errors 4xx 5xx etc, is to use spring framework, example:. redirect to an external url
#RestController
public class MyController implements ErrorController {
private static final String URL = "http://www.blablaba.com";
#RequestMapping(method = RequestMethod.GET)
#ExceptionHandler(RuntimeException.class)
public void handle(final RuntimeException rex, final HttpServletResponse
hsp) throws IOException {
hsp.sendRedirect(getErrorPath());
}
#Override
public String getErrorPath() {
return URL;
}
}
Im not sure the approach they took in the demo but this is what comes to my mind. In your ErrorView you can call UI.getCurrent().getNavigator() and then redirect to the desired URL by getting the URL from the Page.getCurrent() object then running Navigator.navigateTo().

Resources