users@jersey.java.net

Re: [Jersey] mapping put calls (can't have optional/empty payload?)

From: Craig McClanahan <craigmcc_at_gmail.com>
Date: Mon, 7 Jun 2010 15:07:31 -0700

On Mon, Jun 7, 2010 at 2:49 PM, danomano <dshopkins_at_earthlink.net> wrote:
>
> I have a requirement to implement an api as follows:
>
> PUT
> ../resource/<id>
> <body is payload>
>
> Result: new resource is created (error is resource already exists)
>
> PUT
> ../resource/<id>?someField=abc
> <NO BODY>
>
> Result: update the resource such that someField = abc.
>
> I tried mapping this as follows:
>    @PUT
>    @Path("/{resourceId}")
>    public void createOrUpdate(Resource resource,
>                               @PathParam("resourceId") String resourceId,
>                               @QueryParam("someField") Long someField);
>
> however this only appears to work if the Resource payload is present, i.e.
> if I do an HTTP PUT, without a payload the method is never invoked.
>
> I tried mapping as well to 2 seperate methods, one with payload (minus the
> queyParam), and one without the playload but with the queryParam, but that
> was ambigious for jersey..so that didn't work)
>
> Is this mapping not possible?
> (and yes I argued the user should be forced to issue put-update calls with
> the payload rather then the queryparam..but got overruled).
>
> Any advice? (Am I going be stuck with using servlets as my
> interface?..yuk..I could inject an empty <Resource/> I suppose with a
> servletFilter..)

Several things to think about:

(1) Per RFC 2616 Section 9.4[1], a PUT with no body violates the HTTP spec,
     so it's hard to be sympathetic with a complaint that a framework
     like JAX-RS doesn't support that use case.

(2) Even if you moved the "someField=abc" into the body, using
     PUT for partial updates also violates the intent of PUT as defined
     in HTTP. For partial updates, consider using the PATCH method,
     which was recently standardized[2]. (You'll have to define your
     own annotation for it with current versions of JAX-RS, but its easy).

(3) In RFC 2616, Section 9.1, requirements for idempotent requests
     are described -- in particular, the fact that an idempotent can be
     repeated by the client with no negative side effects. The problem
     with using PUT for resource creation is that PUT is required to be
     idempotent, so it is difficult to enforce this requirement unless there
     is some unique identifier within the resource body that will cause
     a duplicate create request to get caught, and thus avoid creating
     two or more records. POST is generally easier to deal with in this
     regard, although you still need to figure out what happens when a
     client, say, doesn't receive any response to an initial POST and
     therefore tries it again. (This, by the way, is why browsers warn you
     when you use the back arrow and then try to submit a form using
     POST again.)

[1] http://www.ietf.org/rfc/rfc2616.txt
[2] http://www.ietf.org/rfc/rfc5789.txt

>
> thanx
> Dan

Craig