Question

I am trying to set up a simple Restful Web-Service which returns either JSON or XML according to the Accept header. I am using Spring, Maven and WebLogic Server. I took the example from this post http://software.sawano.se/2012/03/combining-json-and-xml-in-restful-web.html and tried to improve on it. GET and DELETE is working for both JSON and XML.But PUT and POST gives a "405 Method Not Allowed" Error. I am trying to test this with the Chrome Extension Advanced Rest Client. below is the Response headers.

Status
405 Method Not Allowed Show explanation Loading time: 327

Request headers 
Accept: Application/json
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36
Content-Type: application/x-www-form-urlencoded 
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8


Response headers 
Connection: close
Date: Tue, 11 Feb 2014 15:17:24 GMT 
Content-Length: 34 
Content-Type: text/html 
Allow: GET, DELETE 
X-Powered-By: Servlet/2.5 JSP/2.1
Raw
Parsed

the request body that i give is below:

{
id: 1
name: "manga"
}

My Controller Class is as shown below:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashSet;
import java.util.Set;

@Controller
@RequestMapping("/users")
public class RESTController {
Userlist obj2;
boolean flag=false;
private Logger logger = LoggerFactory.getLogger(getClass());

@RequestMapping(value = "/{id}",method = RequestMethod.GET)
@ResponseBody
public User getUser(@PathVariable int id, @RequestHeader("Accept") String acceptHeader) {
    User temp = new User();
    if(obj2==null)
    {
        temp= new User(0, "Null");
    }
    else   {
        Set<User> set1= obj2.getUsers();
        for(User a:set1)
        {
            if(id==a.getId()) temp=a;
        }
      }
    logger.trace("Serving resource for Accept header: {}", acceptHeader);
    return temp;
}

@RequestMapping(value="",method = RequestMethod.GET)
@ResponseBody
public Userlist getUsers(){
    if(flag==false){
    User new1=new User(1,"Rob");
    User new2=new User(2,"VAN");
    User new3=new User(3,"DAM");
    User new4=new User(4,"Helio");
 Set<User> obj1 =new HashSet<User>();
    obj1.add(new1);
    obj1.add(new2);
    obj1.add(new3);
    obj1.add(new4);
    obj2=new Userlist(obj1);
    flag=true;
    }
    return obj2;
}

@RequestMapping(value="/{id}",method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
public void deleteUser(@PathVariable int id){
    Set<User> set1= obj2.getUsers();
   for(User a:set1)
    {
        if(id==a.getId()) set1.remove(a);
     }
    Userlist obj3=new Userlist(set1);
    obj2=obj3;
    //return obj3;
}

@RequestMapping(value="/{id}",method = RequestMethod.PUT, consumes = "Application/json")
@ResponseStatus(HttpStatus.OK)
public void updateUser(@PathVariable int id, @RequestBody User temp){
    System.out.println("Inside the put function");
        if(temp==null){System.out.println("This is a Null for PUT");}
 }
}

Right now I do not have anything in PUT.

Was it helpful?

Solution 2

Well, apparently I had to change my PUT calling function updateUser. I removed the @Consumes, the @RequestMapping and also added a @ResponseBody to the function. So my method looked like this:

@RequestMapping(value="/{id}",method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public void updateUser(@PathVariable int id, @RequestBody User temp){
    Set<User> set1= obj2.getUsers();
    for(User a:set1)
    {
        if(id==a.getId())
        {
            set1.remove(a);
            a.setId(temp.getId());
            a.setName(temp.getName());
            set1.add(a);
        }
    }
    Userlist obj3=new Userlist(set1);
    obj2=obj3;
}

And it worked!!! Thank you all for the response.

OTHER TIPS

Notice Allowed methods in the response

Connection: close
Date: Tue, 11 Feb 2014 15:17:24 GMT 
Content-Length: 34 
Content-Type: text/html 
Allow: GET, DELETE 
X-Powered-By: Servlet/2.5 JSP/2.1

It accepts only GET and DELETE. Hence, you need to tweak the server to enable PUT and POST as well.

Allow: GET, DELETE

I'm not sure if I am correct, but from the request header that you post:

Request headers

Accept: Application/json

Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8

it seems like you didn't config your request body to JSON type.

I same thing happen with me, If your code is correct and then also give 405 error. this error due to some authorization problem. go to authorization menu and change to "Inherit auth from parent".

Authorization Type options menu Authorization Inherit auth from parent selected

In my case the form (which I cannot modify) was always sending POST.
While in my Web Service I tried to implement GET method (due to lack of documentation I expected that both are allowed).

Thus, it was failing as "Not allowed", since there was no method with POST type on my end.

Changing @GET to @POST above my WS method fixed the issue.

The problem is that POST method is forbidden for Nginx server's static files requests. Here is the workaround:

# Pass 405 as 200 for requested address:

server {
listen       80;
server_name  localhost;

location / {
    root   html;
    index  index.html index.htm;
}

error_page  404     /404.html;
error_page  403     /403.html;

error_page  405     =200 $uri;
}

If using proxy:

# If Nginx is like proxy for Apache:

error_page 405 =200 @405; 

location @405 { 
    root /htdocs; 
    proxy_pass http://localhost:8080; 
}

If using FastCGI:

location ~\.php(.*) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include /etc/nginx/fastcgi_params;
}

Browsers usually use GET, so you can use online tools like ApiTester to test your requests.

Source

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top