-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Separate REST Data Panache controller from resource #11969
Conversation
I assume you want a review from @FroMage ? |
That would be great. I think many of the files could be simply skimmed in a review. Especially the tests because I didn't add any new ones but modified the old ones to comply with the API changes. |
Is there something I could do to help out with this review? Maybe provide more information about the change or try to split the PR up into a few smaller ones? |
@FroMage could you take a look at this one when you get a chance? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late review.
The code is fine. I've some questions about the docs.
But ultimately, the idea seems to be to treat the resource interface as a service/DAO layer that the generated endpoint calls. That's what the implementation looks like.
But then, how am I supposed to add extra endpoints to the resource?
What if I write:
@ResourceProperties(hal = true, path = "my-people")
public interface PeopleResource extends PanacheEntityResource<Person, Long> {
@GET
@Path("extra")
public String extraEndpoint() {
return "Hello";
}
}
Will you copy the extra method into the generated resource class?
@@ -92,7 +92,9 @@ public class PeopleResourceImpl implements PeopleResource { // The actual class | |||
|
|||
@GET | |||
@Produces("application/json") | |||
public Response list(){ | |||
public Response list(@QueryParam("page") @DefaultValue("0") int pageIndex, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So why not return a List<Person>
?
@@ -132,10 +134,10 @@ It can be used in your resource interface: | |||
@ResourceProperties(hal = true, path = "my-people") | |||
public interface PeopleResource extends PanacheEntityResource<Person, Long> { | |||
@MethodProperties(path = "all") | |||
Response list(); | |||
Person list(Page page, Sort sort); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it List<Person>
?
Also it feels weird that these are Page
and Sort
when the generated code you showed up there uses int
and String
, is it normal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's List<Person>
my bad. I think I'll rewrite the doc to clarify the differences better.
|
||
@MethodProperties(exposed = false) | ||
void delete(Long id); | ||
boolean delete(Long id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We end up returning a boolean response?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Since I separated the RestDataResource
implementation from a JAX-RS resource I decided to add a return value to the delete method so that a JAX-RS resource would know whether an entity was deleted or not and return either 204 or 404 response.
You understood the main idea correctly. This separates data access from JAX-RS. User would define an interface that specifies the data access which we could generate based on the actual interface used and customization annotations. The JAX-RS part is hidden from the user and is the same for all data access implementations. It defines JAX-RS annotations and then calls generated data access classes (the ones that implement The custom method logic is up for discussion. But I was imagining extra methods that would follow a particular naming pattern. For example, |
Since this haven't been merged yet, I'll add some changes over the next few days. I ran into an issue working on Spring Data REST extension that could benefit from this PR if only it would be slightly changed. |
84f67e5
to
63158a8
Compare
I'm not sure about this way to add endpoints. I feel like we're adding a new way to declare endpoints that is not necessarily going to be the same new way we end up adding to regular REST endpoints. We are already talking of making I think it'd be better if I could add normal endpoint methods, either pure JAX-RS (at the moment) or whatever nice way we come up with in the future. OTOH ATM we don't allow extra endpoints, so that discussion can wait, but I'd like to make sure that we have a plan for when we allow that. IF we allow it. Perhaps it makes sense to just not allow adding any extra endpoint, and the user will have to place them somewhere else. Do we have use-cases for adding extra endpoints? Or replacing one? |
Or did I get this wrong and your idea is to allow (in the future) the user to override what happens inside the existing pre-defined endpoints? As opposed to modifying the endpoint "REST signature" or adding new endpoints? |
Well, we don't have to introduce custom endpoints now and this change doesn't do it. The main improvement, in my mind, is that the data access implementation is separated from JAX-RS implementation (before data access was done in JAX-RS class implementation). This gives more freedom when defining custom things like adding query without having to change user facing interface, having custom data access implementation (e.g. Spring Data REST extension would implement it differently than Mongo and Hibernate does). |
206eed9
to
f54ec02
Compare
So, to recap, the new design will take this user code: public interface/class MyStuff implements RestDataResource<Stuff> {} And turn it into: @Path("mystuff")
public class MyStuffEndpoint {
@Inject
MyStuffDAO myStuffDAO;
@GET
public List<Stuff> list(@QueryParam String sort, @QueryParam int page, @QueryParam int pageSize) {
return myStuffDAO.list(parseSort(sort), makePage(page, pageSize));
}
…
}
@Singleton
public class MyStuffDAO extends/implements MyStuff {
public List<Stuff> list(Sort sort, Page page) {
return Stuff.find(sort).page(page).list();
}
…
} So we get two beans: endpoint and DAO. The question was how do we allow users to add or modify methods, given that they would end up in the DAO since the endpoint one doesn't implement anything and is only a JAXRS shell to the DAO. Thinking back on the reasons why people would want to add methods:
As for modifying methods:
As a result, I think the current proposal is fine. It has consequences, but they all seem acceptable. |
You do have a conflict, though. |
Sorry I closed it by accident. |
I'll fix the conflict in a bit. We merged a couple of related commits a day or two ago. |
f54ec02
to
6caddc6
Compare
@FroMage conflicts resolved. |
This change separates a generated REST Data with Panache JAX-RS controller class from a generated
RestDataResource
class. Here are the main benefits of this separation.RestDataResource
interface that is used by a user is more user-friendly. JAX-RS Response result type is replaced with type-safe interfaces such asList<T>
or 'T'.list
method hasPage
andSort
as parameters instead of integers and strings.RestDataResource
. This allows methods to have different definitions depending on the configuration. E.g. if pagination is disabled, page index and size parameters are not defined and as a result not shown in an OpenAPI spec.UriInfo
to access them.@ResourceProperties
and@MethodProperties
are now checked when generating methods. Generated code is now smaller because it can avoid unnecessary runtime checks.This PR also fixes #11391.