4

I'm trying to edit my create method in my REST webservice so it should return the newly created ID from the object. I've been trying for the past two days but I must be doing something terribly wrong...

This is the edited create method on the server side:

@POST
@Consumes({"application/xml", "application/json"})
@Path("withID")
@Produces("text/plain")
public String create2(Users entity) {
    getEntityManager().persist(entity);
    getEntityManager().flush();
    System.out.println("new id: " + entity.getId());
    return String.valueOf(entity.getId());
}

It is based on a (by netbeans) generated count() method as shown below:

@GET
@Path("count")
@Produces("text/plain")
public String countREST() {
    return String.valueOf(super.count());
}

If I do a request from my client to add a new Users object, it works like as expected. The new user is beeing added to the database. In the GlassFish server log, I see the newly created ID shown by the System.out.println command. However, if I do a test via the TestRestful Web Services in netbeans, paste the client generated XML code at the correct window and hit the TEST button, I receive a HTTP Status 415 - Unsupported Media Type error.

I did some research and found this question. So my guess instead of returning a String, I should return a Response object with a 201 CREATED status and adjust the header or something? I checked out the spring example but as I am not using spring, I have no clue how to adjust the create2 method code... however I did a try but I'm missing some pieces:

@POST
@Consumes({"application/xml", "application/json"})
@Path("withID")
@Produces("text/plain") //should this change to application/xml?
public Response create2(Users entity) {
    getEntityManager().persist(entity);
    getEntityManager().flush();
    System.out.println("new id: " + entity.getId());

    //Response response = Response.created(... + "withID/" + entity.getId()); //response need an URI, can I get this through the entity object?

    return Response.status(200).entity(entity.getId().toString()).build();    
}

I hope that I'm on the right track. Sorry for the long post, hope someone can help me out here. Thanks in advance!

Edit: working example now:

@POST
@Consumes({"application/xml"})
@Path("withID")
@Produces({"application/xml"})
public Response create2(Users entity) {
    getEntityManager().persist(entity);
    getEntityManager().flush();
    return Response.status(201).entity(entity.getId().toString()).build();
}
Community
  • 1
  • 1
Perneel
  • 3,317
  • 7
  • 45
  • 66
  • you don't need to adjust any header. Response.created() automatically puts URI you've provided to http response as "Location" header. So looks like you already have a solution. – Pavel Bucek Oct 19 '12 at 10:02
  • Hi Pavel, I only find in `javax.ws.rs.core.Response` following method​`public static Response.ResponseBuilder created(URI location)`. Create a new ResponseBuilder for a created resource, set the location header using the supplied value. – Perneel Oct 19 '12 at 12:05

2 Answers2

1

I don't know about the NetBeans stuff, we're using Spring.. But returning a Response object is a good idea, we always do that and we also return the ID for a create:

return Response.status(200).entity(createdObject.getId().toString()).build();

Unsupported MediaType is quite annoying.. Not sure what you're talking about when you mention client generated xml data.. We're using JSON and even though the response is just a simple string, we tell the create method to produce json:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public Response create(T source) {
}

Simple test we use on the command line:

$ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"id":95, "additional":"stuff..."}' "http://localhost:8080/rest/resource"

Well, good luck. Looks like you're on the right track.

Pete
  • 10,720
  • 25
  • 94
  • 139
  • Hi Pete, thanks already for your answer. I'm gonna try this out asap. With 'client generated xml data' I actually ment the XML string that is sent to the web service (which consumes it) – Perneel Oct 19 '12 at 12:19
  • I tested it in the meanwhile but still got the same **HTTP Status 415 - Unsupported Media Type** error. Description: The server refused this request because the request entity is in a format not supported by the requested resource for the requested method (Unsupported Media Type). – Perneel Oct 19 '12 at 12:35
  • Hm.. Either the xml you send is wrong or your service cannot handle that specific format.. Can't help you there, as we're using JSON, which I can easily test by sending a `curl` request in my command line. I'll add what I do for testing in my post.. Don't know if that works for xml as well so you have an alternative for testing. Could be netBeans is messing up the call, don't know.. – Pete Oct 19 '12 at 12:42
  • Hm I doubt that the XML is the problem as the user is actually beeing added? If there would be a fault in the XML I think that the user wouldn't be added... – Perneel Oct 19 '12 at 14:48
  • Okay, returning id's now works with the code you provided Pete. I can succesfully retrieve the ID on my client, however for some strange reason I keep getting the 415 error when testing the method via the browser... Anyway, thanks a lot! – Perneel Oct 20 '12 at 13:39
  • And for people struggeling with the client side: http://www.mkyong.com/webservices/jax-rs/restful-java-client-with-jersey-client/ – Perneel Oct 20 '12 at 13:55
0

Instead of returning some custom blob, just use the protocol.

So, consider using a location header in your response with the uri to your new resource. You are doing a rest service so of course your ids are URIs (right ?).

Jim Webber wrote a great book on designing REST web services called REST in Practice that explains in great detail how to design REST apis based on simple principles like this.

Jilles van Gurp
  • 7,927
  • 4
  • 38
  • 46