-
Notifications
You must be signed in to change notification settings - Fork 7.4k
[Admin API v2] Skeleton prototype #39322
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
[Admin API v2] Skeleton prototype #39322
Conversation
d84fce8
to
100131b
Compare
6ee7a49
to
dfe6650
Compare
Looks good @mabartos, here's some initial thoughts.
By API you are referring to the entire Admin API Rest layer correct? Basically what is contributed by the AdminApiSpi and related classes? Are you splitting it out of concern the default impl brings in dependencies that devs shouldn't otherwise be using? If not, I would advocate for using a single module for the default impl and the spis, rather than splitting it, as it seems likely that anything a dev would want to do here would simply extend the existing logic (given the rigidity of the rest interface), rather than completely rewrite it. Are there some thoughts about what kind of customizations users would want to do at this layer? I added some musing about field mix-in below - it would be good to expand on how this abstraction point could be used.
That seems good, especially if it is already productized. Since it is based on code generation there isn't a worry about the apis getting out-of-sync. Another thought is that Representations as records are concise, but may be too limiting down the road - some logic has ended up in the current Representation classes, like the DeviceRepresentation.setBrowser method. They are also not extensible making them a hard contract for the API Spi. That may be taking away some of the extensiblity of this layer. For example if you wanted a straight-forward way to mixin some fields on a representation in your custom api. I know this is not trivial - this would also require the base class to support something similar to what is done in fabric8 with additionalProperties on all Kubernetes resources, so that you could preserve that on deserialization, and of course that would need to be accounted for in the openapi metadata via something like preserve unknown. An alternative (which I know some would be reluctant to consider, but if we're already bringing in MapStruct...) is the lombok Data annotation - that gives you the concise record like definition, but is an actual class that you can further refine.
More than likely yes - that is the layer which would be most easily extensible by something like the graphql community project.
Alternatively if we cannot come up with compelling scenarios where the entire rest spis are extended / replaced, then we should focus more on what the business layer definition as the point of extensibility. |
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.
Unreported flaky test detected, please review
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.webauthn.account.WebAuthnSigningInTest#categoriesTestKeycloak CI - WebAuthn IT (firefox)
org.keycloak.testsuite.broker.KcOidcBrokerTest#loginWithExistingUserWithBruteForceEnabledKeycloak CI - Java Distribution IT (windows-latest - temurin - 24)
|
@shawkins Thanks for the review! I'll try to answer incrementally.
Yes.
Yes, it will probably make more sense to merge the default impl with the API contracts. I wanted to have them as separate units to have a clean code and "only-contract" module to have it easily used without these additional deps (but there will not be so many more perhaps, so it's ok).
The intention behind this is that devs might provide some additional endpoints outside of the Admin API v2 contract. There are some possibilities, but this might be clean to just use SPI for ClientsAPI for instance. ..... |
Yes, from what I checked, it's productized on our side. I think it's gonna be better approach than using the RepresentationToModel <--> ModelToRepresentation classes.
Yes, in terms of extendability, a normal class seems a better direction to go.
I'd say it's some sort of standard to use Lombok in Java apps as the maturity of it is high and there are multiple resources available. I would not probably resist so much. Yes, as you mentioned - if we're bringing in MapStruct ;)
Make sense.
Yes, we can discuss. I'll try to update the skeleton based on the feedback and how I think it might be good to have it :) |
dfe6650
to
e87db8b
Compare
Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com>
1b3db76
to
92fa00d
Compare
rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java
Show resolved
Hide resolved
Just wanted to muse more on versioning. With this pr you can contribute different implemenations of v2, which we'll need to come up with more use-cases for. At an even coarser level there's Admin API v1 vs v2, with additional revisions to follow in the future. We may want to go back and similarly encapsulate the v1 implementation so that users via profile features can run 1 or more of our admin apis of their choosing. Versioning at the resource level is something we've only touched on a little in the meetings. We talked about it in terms of the "default problem" and a little in comparison to how kubernetes handles things. So it's worth touching on here - from a specific version of the admin api, do we want to support multiple versions of a given resource? That is could you submit and even retrieve Client v1 (for example the ClientRepresentation shown so far in this pr) and Client v2 (a ClientRepresentation with different fields and / or defaults)? If the answer is uncategorically yes, that will greatly complicate things. More pragmatically we may want to be able to account for this like how we allow our CRDs to change over time - we will allow changes that are schema compatible, but we may still want to capture in the representation what version is being used (to determine what defaults are applicable for example) and if the object model can potentially be used in a way that spans multiple versions, we may need to add something like the additionalProperties handling mentioned in the previous comment. |
It will probably not be necessary to introduce it as we already have the AdminRealmResourceProvider as users might potentially add their resources/endpoints that way. I'll remove the abstraction.
Yes, versioning of these resources should be a good way on how to build a good API - if we are able to store some changelog/set of defaults for versions. Not sure how difficult would it be to manage field changes over different versions. It is possible out of scope of this PR as even the code introduced here can be changed with no difficulties. And agree that we need some mechanism to store some metadata (or the additionalProperties as you mentioned. In that case, we'd need to probably update even the Model interfaces to contain some metadata - as some Model interfaces already contains Map of attributes, but might be separated as they can represent some bigger business value + not all models have the map. |
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
92fa00d
to
307c4d7
Compare
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.
Nice work @mabartos! It's a good start.
rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java
Outdated
Show resolved
Hide resolved
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.
Just a side note. Based on a comment from Stian we might in the end keep the structure solid, unsplitted. But that's for a follow up.
<dependency> | ||
<groupId>org.mapstruct</groupId> | ||
<artifactId>mapstruct</artifactId> | ||
<version>${org.mapstruct.version}</version> | ||
</dependency> |
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.
Not sure about productization but I assume it's build time only processor.
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.
From what I've checked, it is fully productized.
Ad versioning. It's out of scope of this PR, IMHO. We'll tackle it soon as a follow-up. |
…entsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Latest changes
|
Signed-off-by: Martin Bartoš <mabartos@redhat.com>
* Add new ClientRepresentation Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add APIs Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ApiModelMapper SPI Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add MapStruct as default ApiModelMapper Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default APIs implementations Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Provide Service SPI and ClientService Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default Keycloak services and Client service Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ModelMapper to shared modules Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Implement Client service, add ServiceException class Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use ClientService in Client REST API Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Update rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Fix ModelMapperSpi Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use /admin/api/v2 as a root path Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Support latest API version by default Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Rename path param to comply with API spec Signed-off-by: Martin Bartoš <mabartos@redhat.com> --------- Signed-off-by: Martin Bartoš <mabartos@redhat.com> Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
* Add new ClientRepresentation Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add APIs Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ApiModelMapper SPI Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add MapStruct as default ApiModelMapper Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default APIs implementations Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Provide Service SPI and ClientService Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default Keycloak services and Client service Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ModelMapper to shared modules Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Implement Client service, add ServiceException class Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use ClientService in Client REST API Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Update rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Fix ModelMapperSpi Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use /admin/api/v2 as a root path Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Support latest API version by default Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Rename path param to comply with API spec Signed-off-by: Martin Bartoš <mabartos@redhat.com> --------- Signed-off-by: Martin Bartoš <mabartos@redhat.com> Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
* Add new ClientRepresentation Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add APIs Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ApiModelMapper SPI Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add MapStruct as default ApiModelMapper Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default APIs implementations Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Provide Service SPI and ClientService Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default Keycloak services and Client service Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ModelMapper to shared modules Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Implement Client service, add ServiceException class Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use ClientService in Client REST API Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Update rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Fix ModelMapperSpi Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use /admin/api/v2 as a root path Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Support latest API version by default Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Rename path param to comply with API spec Signed-off-by: Martin Bartoš <mabartos@redhat.com> --------- Signed-off-by: Martin Bartoš <mabartos@redhat.com> Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
* Add new ClientRepresentation Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add APIs Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ApiModelMapper SPI Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add MapStruct as default ApiModelMapper Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default APIs implementations Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Provide Service SPI and ClientService Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default Keycloak services and Client service Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ModelMapper to shared modules Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Implement Client service, add ServiceException class Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use ClientService in Client REST API Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Update rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Fix ModelMapperSpi Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use /admin/api/v2 as a root path Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Support latest API version by default Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Rename path param to comply with API spec Signed-off-by: Martin Bartoš <mabartos@redhat.com> --------- Signed-off-by: Martin Bartoš <mabartos@redhat.com> Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
* Add new ClientRepresentation Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add APIs Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ApiModelMapper SPI Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add MapStruct as default ApiModelMapper Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default APIs implementations Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Provide Service SPI and ClientService Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default Keycloak services and Client service Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ModelMapper to shared modules Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Implement Client service, add ServiceException class Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use ClientService in Client REST API Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Update rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Fix ModelMapperSpi Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use /admin/api/v2 as a root path Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Support latest API version by default Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Rename path param to comply with API spec Signed-off-by: Martin Bartoš <mabartos@redhat.com> --------- Signed-off-by: Martin Bartoš <mabartos@redhat.com> Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
* Add new ClientRepresentation Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add APIs Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ApiModelMapper SPI Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add MapStruct as default ApiModelMapper Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default APIs implementations Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Provide Service SPI and ClientService Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add default Keycloak services and Client service Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Add ModelMapper to shared modules Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Implement Client service, add ServiceException class Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use ClientService in Client REST API Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Update rest/admin-api/src/main/java/org/keycloak/admin/api/client/ClientsApi.java Co-authored-by: Václav Muzikář <vaclav@muzikari.cz> Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Fix ModelMapperSpi Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Use /admin/api/v2 as a root path Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Support latest API version by default Signed-off-by: Martin Bartoš <mabartos@redhat.com> * Rename path param to comply with API spec Signed-off-by: Martin Bartoš <mabartos@redhat.com> --------- Signed-off-by: Martin Bartoš <mabartos@redhat.com> Co-authored-by: Peter Zaoral <pzaoral@redhat.com> Co-authored-by: Václav Muzikář <vmuzikar@redhat.com> Co-authored-by: Václav Muzikář <vaclav@muzikari.cz>
Try it out
Get clients
or
Get client
or
If you want to retrieve the full representation, add the query param
runtime=true
Create client
or
For the second execution, it should return 409. For PUT, it will update the client (not implemented yet).
Questions
Do we want to create some middle service layer to take care of the business logic and authz? And on the REST level, we could only do HTTP/REST stuff and mapping Model->Representation. Given that we could provide the SPI for each part of the API, I don't think it's worth to include additional abstraction layer.YES