Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Add JAX-RS PATCH annotation #36

Merged

Conversation

EricChristensen
Copy link
Contributor

@EricChristensen EricChristensen commented May 15, 2017

What was changed? Why is this necessary?

From issue 21 JAX-RS does not have a PATCH annotation for supporting HTTP patch method like it does for others like GET or POST. We should add a PATCH annotation that can be used for handling the patch HTTP method.

How was it tested?

The PATCH annotation was tested by consuming this change in a test branch of a project that already consumes beadledom. In this project, a simple resource that uses the PATCH annotation was used to manually make sure that the behavior performed as expected. Two unit tests were also added to the project to 1. Ensure that PATCH is used and behaves as expected and 2. PATCH is used and performs an operation on the server to ensure that serialization works as expected.

How to test

  • mvn clean install -U

Reviewers

*
* @author Eric Christensen
*/
class PATCHSpec extends FunSpec with BeforeAndAfterAll with ShouldMatchers with MockitoSugar {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@EricChristensen EricChristensen May 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PATCH used with an actual stood up service in the "retrieves the resources from different clients" test d582c3a

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be a separate test directly in the describe("Proxied Clients") block that tests only that patch works.

response.getStatus shouldBe 200
}

it("should change the request model fields") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to have these two test, when you are calling the function with the same input twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are indeed the same function calls with the same parameters but it seemed appropriate to have two different "it" descriptors, one for just making sure that PATCH is called successfully and one to make sure that serialization takes place properly by making sure the server performed a change and returned it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would merge the two into one test. We are not testing two different aspects of the method here. Status code 200 means the request is served successfully. For PATCH a successful request mean that the resource is patched correctly. So, having these two checks in one test makes sense IMO.

response.getStatus shouldBe 200

val newModel: FakeModel = mapper.readValue(response.getContentAsString, classOf[FakeModel])
newModel.name shouldBe "newName"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory, if this was a real patch shouldn't these responses be what you sent to the patch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PATCH resource updates the request that was sent to it. Normally the update would be to an existing resource in a database, but for the purposes of just performing an operation on the server this is fine.

@@ -28,6 +28,10 @@
@JsonProperty("inner_models")
public List<FakeInnerModel> innerModels;

public FakeModel() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you add a default constructor? the only place I see you using it is here where you use the constructor that already exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default constructer and the setters were added to make the creating of the FakeModel more like the builder pattern. It is used in the Spec at the recommendation of Brian.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't break of the existing tests using this model did we? I can't imagine so but you never know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope all tests pass even after model change

model.setName("newName");
return Response.ok(model).build();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@b-boogaard
Copy link
Contributor

b-boogaard commented May 16, 2017

I'm not sure exactly what we would say about it, but it seems like we would want to add the fact we added a @PATCH annotation to the manual for the jax-rs module

Edit:

In case you're not sure, the changes would be made under the docs module. We use reStructuredText as our markup.

@EricChristensen
Copy link
Contributor Author

@b-boogaard what do you think of this? a1fac9f

@b-boogaard
Copy link
Contributor

I think I would add it either above or below the Correlation-Id header. I think I would want to link to https://tools.ietf.org/html/rfc5789 the rfc that added PATCH to HTTP. Then give an interface like example of a resource using it, pointing out it can be used just like the others that are defined by JAX-RS.

@johnlcox @sparuvu @lal-s @nimeshsubramanian thoughts?

@EricChristensen
Copy link
Contributor Author

@b-boogaard
Copy link
Contributor

How about something like:

JAX-RS 2.0 (see section 3.3 for Resource Methods) does not require implementations to support the PATCH HTTP method. This is likely do to the fact that PATCH was introduced in a later rfc that added the new HTTP method to the already existing HTTP/1.1 specification.

@PATCH was added to beadledom-jaxrs to allow services to support partial updates without the need of overloading @POST. The annotation has no opinion on how the service decides to implement the resource performing the PATCH operation. Implementing services have the freedom to support JSON Patch and/or JSON Merge Patch.

As long as a service has beadledom-jaxrs as a dependency @PATCH can be used just like any of the HTTP method annotations defined by JAX-RS. Below is a small example of @PATCH being used in an interface for a resource.

code example here

I think this could use a bit a clean up but I feel like it reads a bit better. Thoughts?


val jsonNewTwo = JsonTwo.create("New Json", "Hola")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please differentiate jsonNewTwo from jsonNewOne (just change Hola to Hola1 and Hola2 or something simple)

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please add some javadoc to this.

response.getStatus shouldBe 200
}

it("should change the request model fields") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would merge the two into one test. We are not testing two different aspects of the method here. Status code 200 means the request is served successfully. For PATCH a successful request mean that the resource is patched correctly. So, having these two checks in one test makes sense IMO.

PatchObject patchObject);

.. _RFC: https://tools.ietf.org/html/rfc5789

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about this?

PATCH
--------------

`PATCH <https://github.com/ktoso/maven-git-commit-id-plugin>`_ is a HTTP verb (similar to GET, POST, DELETE, PUT) to push partial changes to the REST resource. JAX-RS by default doesn't support PATCH hence Beadledom adds the support for PATCH explicitly.

For more details on the PATCH method visit the PATCH RFC_.

To use the PATCH method and annotation for your resource, simply annotate your JAX-RS resource method with the PATCH annotation as shown below

.. code-block:: java

 @PATCH
 @Path("path/to/patch")
 @Produces(MediaType.APPLICATION_JSON)
 public Response patch(
   @PathParam("id") final Long id,
   @ApiParam(value = "changes to make to the object with the specified id")
   PatchObject patchObject);

.. _RFC: https://tools.ietf.org/html/rfc5789

@EricChristensen
Copy link
Contributor Author

@sparuvu comments addressed here. @b-boogaard I went with Sundeeps description of the annotation in the jaxrs.rst. Concise, simple and exactly what the user needs to know. I removed the git url that was linked in the description because don't see how it relates to PATCH at all...

/**
* Indicates that the annotated method responds to HTTP PATCH requests.
*
* @author John Leacox
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be you :) and not John

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you insist :) bb8be52

import javax.ws.rs.HttpMethod;

/**
* Indicates that the annotated method responds to HTTP PATCH requests.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be - Annotation to support the Http PATCH requests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current description is consistent with other jaxrs http annotation descriptions https://docs.oracle.com/javaee/7/api/javax/ws/rs/PUT.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to matching the jaxrs descriptions.

PATCH
--------------

`PATCH is a HTTP verb (similar to GET, POST, DELETE, PUT) to push partial changes to the REST resource. JAX-RS by default doesn't support PATCH hence Beadledom adds the support for PATCH explicitly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it would be good if we could link the PATCH to this wiki article - https://en.wikipedia.org/wiki/Patch_verb

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

link to wiki on brian's version of rst f388ee2

@sparuvu
Copy link
Contributor

sparuvu commented May 17, 2017

@sparuvu comments addressed here. @b-boogaard I went with Sundeeps description of the annotation in the jaxrs.rst. Concise, simple and exactly what the user needs to know. I removed the git url that was linked in the description because don't see how it relates to PATCH at all...

I think I like what Brian has. It is more detailed and more importantly it points that implementing services have the freedom to implement whatever PATCH algorithm they want to go with.

@EricChristensen
Copy link
Contributor Author

@sparuvu brian's version of jaxrs.rst bb8be52

@@ -4,4 +4,5 @@
<suppress files="generated-sources" checks=".*"/>
<suppress files="generated-test-sources" checks=".*"/>
<suppress files="com.cerner.beadledom.client.resteasy.ApacheHttpClient4Dot3Engine" checks=".*"/>
<suppress files="com.cerner.beadledom.jaxrs.PATCH" checks="AbbreviationAsWordInName" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just want to confirm this is necessary because checkstyle is expecting the classname to be Patch?

If JAX-RS hadn't already set the standard for these annotations we would name it that way, but PATCH is correct in following the standard of the other JAX-RS annotations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that is the reason.

/**
* Indicates that the annotated method responds to HTTP PATCH requests.
*
* @author Eric Christensen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @since 2.5 below author.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johnlcox
Copy link
Contributor

+1 to @b-boogaard's doc text.

@johnlcox
Copy link
Contributor

Will it be desired for beadledom to include a class with additional mediatypes like json-patch and json-merge-patch that can be used similarly to MediaType.APPLICATION_JSON?

This questions came to mind while looking at this review, but I think it would be a separate code change if it is desired.

@EricChristensen
Copy link
Contributor Author

@johnlcox we are planning to use json-merge-patch in our application so yes I would say that is a desired behavior.

@b-boogaard
Copy link
Contributor

I think adding the media types for patch is a good idea.

@EricChristensen
Copy link
Contributor Author

Is there any reason that adding the media types could not be done in this code change?

@johnlcox
Copy link
Contributor

I'd rather see it as a separate code change because I think there needs to be some discussion on the strategy we want to use for supporting additional media types in general. This probably warrants starting with an issue for that discussion prior to any code changes.

@johnlcox
Copy link
Contributor

+1

1 similar comment
@b-boogaard
Copy link
Contributor

+1

@johnlcox
Copy link
Contributor

I logged #37 for the media type discussion.

@sparuvu
Copy link
Contributor

sparuvu commented May 18, 2017

+1

1 similar comment
@nimeshsubramanian
Copy link

+1

@b-boogaard b-boogaard merged commit e83ff7c into cerner:master May 18, 2017
@b-boogaard b-boogaard added this to the 2.5 milestone May 19, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants