HTTP Status 405 - Method Not Allowed using Rest webservice - rest

I am getting correct result when invoking method #GET, but as soon as i use #PUT method using URI localhost:8080/MyProject/rest/calculator/23, it is giving error i.e. HTTP Status 405 - Method Not Allowed.
Code is below:
#Path("/calculator")
public class CalcyRest {
#GET
#Path("plain/{name}")
#Produces(MediaType.TEXT_PLAIN)
public String getplain(#PathParam("name") String name){
return "this is plain text ... Hello : "+name;
}
#GET
#Produces(MediaType.TEXT_HTML)
public String getplain(){
return "<html><head><title></title></head><body><h1>this is html</h1></body> </html>";
}
#PUT
#Path("{studentRollNo}")
#Produces(MediaType.TEXT_PLAIN)
public String updateCal(#PathParam("studentRollNo") String strn){
return "updated successfully!";
}
}

First of all, you didn't really ask a question. You are just describing your problem. Here on SO it is very important to know how to ask a question.
Secondly, it would have been a good idea to have posted the URL for the GET request, in order for us to notice some possible subtle mistakes.
Thirdly, please make sure your request URL is good. I was expecting to see something like localhost:8080/MyProject/calculator/23. Why did you put rest inside the URL?

Check your web server configuration. $1 says it is set to reject PUT requests.

Related

HTTP Status 405 – Method Not Allowed | Jersey | REST WS Call | PUT & DELETE

-Code for Exposing Resource:
#Path("/messages")
public class MessageResource {
#PUT
#Path("/{messageId}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_HTML})
public MessageEntity updateMessage(MessageEntity messageEntity, #PathParam("messageId") long messageId) {
messageEntity.setMessageId(messageId);
return new MessageService().updateMessage(messageEntity);
}
}
URI to test: http://localhost:8080/rest-webservice-app/webapi/messages/1
I am testing using Postman (So not a problem with Method being called), and every time I do get the same error :
HTTP Status 405 – Method Not Allowed
I snooped around stack overflow and other blogs/forums for the answer, but nothing seems to work.
Read about the firewalls of the PUT/DELETE request too but doesn't seem to be a firewall issue in case we are testing in local dev env.
The POST and GET are working fine.
The issue is with DELETE and POST.
Can somebody help me out with this?
Thanks.

How to Pass object to REST Get Method

I am using Jersey Rest implementation. There are one Rest Services Called HelloWorld. See the below code.
Please consider this code as reference not as compiled code.
#Path("helloWorld")
public class HelloWorld{
#Path("test")
#Produces(...)
#Consum(...)
#GET
public Response test(Person person){
System.out.println(person);
}
}
I am using Jersey client to sent the request.
Here My question is apart from POST method is there any way to send the object to GET method directly. Instead of QueryString.
Please let me if there is any way to do so.
Thanks
So the problem shouldn't be with the server. I did a few tests on different servers (not weblogic as I don't use it) and all of them seem to have no problems accepting a body in the GET request. The problem seem to be with the client. To test I used the following code
ClientBuilder.newClient()
.target("http://localhost:8080/api/get-body")
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.request()
.method(HttpMethod.GET, Entity.text("Hello World"));
The SUPPRESS_HTTP_COMPLIANCE_VALIDATION allows us to pass a body to the request. If we didn't use this, then we would get an error.
The problem with this code, is that even though we set this override property, the client completely overrides the GET method and automatically makes it a POST method, so I would get back a 405 Method Not Allowed.
The solution I came up with is to just allow the client to set a header, e.g. X-GET-BODY-OVERRIDE, and then use a #PreMatching filter on the server side to check for this header. If the header is present, then just change the method to a GET
#Provider
#PreMatching
public class GetWithBodyFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext request) throws IOException {
String getOverride = request.getHeaderString("X-GET-BODY-OVERRIDE");
if (getOverride != null && "true".equalsIgnoreCase(getOverride)) {
request.setMethod(HttpMethod.GET);
}
}
}
Then just register the filter with the server side. On the client, you would simply need to add the header
ClientBuilder.newClient()
.target("http://localhost:8080/api/get-body")
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.request()
.header("X-GET-BODY-OVERRIDE", "True")
.method(HttpMethod.GET, Entity.text("Hello World"));
This solution is good because it takes into account more than just the Jersey client, in regards with being able to send a body in the GET request.

How to create meaningful REST response messages?

I have created a REST service and I was wondering what the best practice was for sending meaningful messages to a GET request. Basically my GET request returns a specific object, something like this;
#GET
#Path("/examsple")
#Produces(MediaType.APPLICATION_JSON)
public List<SomeObject> retrieveSomeObjs() {
List<SomeObject> result = new ArrayList<>();
try {
result = ... Get SomeObjects ...;
} catch (Exception e) {
... Deal with exception ...
}
return result;
}
That works great except when there is an error the response just sends back an empty List! What would be more useful would be a message that explains what the problem is. However I cant send back a String message because the return type is List!
My current solution is to change the return type to a Map and then I can return the object wrapped in the Map along with any messages. However its a little messy on the client side and I was wondering if there was either an inbuilt solution or an 'accepted' solution for this.
If the client has made an error then use HTTP Response codes. If an item is not found then your response would be a 404 Not Found. If the user does not have permissions to access an object then return a 403 Forbidden. Currently you are responding with a 200 OK saying everything is OK when it's not.
If it's an error at the server side you don't really want to be sending that information to your clients. Catch the error on the server and do something meaningful with it (like log it) so you can change the code so it doesn't happen again.
You could return an HTTP error status code in the header and a JSON response body with an object describing the exception.
As already mentioned some common error codes for GET requests include:
301 Moved Permanently - If the resource has been moved
400 Bad Request - If the client request is unaccaptable, i.e. if the client sends none-sense parameters in the request
401 Unauthorized - If the client did not provide any valid credentials
403 Forbidden - If the client is authorized but not allowed to perform the request (you can also return a 404 in this case to conceal that this resource exists at all)
404 Not Found - If the requested resource could not be found
I usually create a POJO to represent these error messages and then return it using a Jersey Response object.
For example the error object could look like this:
public class ApiError {
private String status;
private String code;
private String message;
private String developerMessage;
// Getters and Setters here
}
To return it you can do the following (i.e. in your catch block or your custom ExceptionMapper):
ApiError error = new ApiError("409", "409-1", message, developerMessage);
return Response.status(Response.Status.CONFLICT).entity(error).build();
This way you can provide nicely formatted JSON/XML error messages containing custom error codes and further information for the developer. The error entities will get serialized according to your #Produces annotation.

create a Jax-RS RESTful service that accepts both POST and GET?

I'm converting one of my existing service to become RESTful and I've got the basic things working with RestEasy. Some of my client apps should be able to execute both GET and POST requests to several services. I'm just seeking if there is any easy way around jax-rs to specify that API should accept both GETs and POSTs. Following you can find a test method, let me know if you see any way around without duplicating this in another class with #GET and #QueryParam.
#POST
#Path("/add")
public Response testREST(#FormParam("paraA") String paraA,
#FormParam("paraB") int paraB) {
return Response.status(200)
.entity("Test my input : " + paraA + ", age : " + paraB)
.build();
}
Just put your method body in another method and declare a public method for each HTTP verb:
#Controller
#Path("/foo-controller")
public class MyController {
#GET
#Path("/thing")
public Response getStuff() {
return doStuff();
}
#POST
#Path("/thing")
public Response postStuff() {
return doStuff();
}
private Response doStuff() {
// Do the stuff...
return Response.status(200)
.entity("Done")
.build();
}
}
As wikipedia says, an API is RESTful if it is a collection of resources with four defined aspects:
the base URI for the web service, such as http://example.com/resources/
the Internet media type of the data supported by the web service. This is often XML but can be any other valid Internet media type providing that it is a valid hypertext standard.
the set of operations supported by the web service using HTTP methods (e.g., GET, PUT, POST, or DELETE).
The API must be hypertext driven.
By diminishing the difference between GET and POST you're violating the third aspect.
If this scenario fits for all your resources you could create a ServletFilter which wraps the request and will return Get or Post everytime the method will be requested.

How to sort dojox.grid.DataGrid with wink-based REST API?

I'm using the Dojo datagrid client side, it works well and according to documentation it generates the following GET request when clicking on the column header:
GET http://localhost:8080/books/rest/books?sort(+isbn)
Problem is that I can't interpret the query parameter "sort(+isbn)" on the server side using the Apache Wink framework, because there's no value set for it. E.g. I'd expect something like "sort=+isbn" instead.
Here's my server side code:
#Path("/books")
public class BookServiceImpl implements BookService {
...
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getBook(#QueryParam("sort") String sortBy) {
System.out.println("Received Queryparam for sort is " + sortBy);
return "";
}
}
Since "sort(+isbn)" has no value assigned to it, it appears to be an invalid query parameter. Not sure why Dojo datagrid uses this convention.
Would appreciate help as to how to work around this on the Java side, ideally using Wink or another mechanism to process GET requests.
Try to use #Context UriInfo to get the full uri info, call to UriInfo.getQueryParameters to get all query params. I believe sort(+isbn) will be there.