Rest Client
Implemented in 5.3
Abstract
The goal is to:
- provide easy-to-use and configurable client for REST calls that can be reused by many other integrations
- have a ‘RestWorkbench’ that will be able to display response in a readable way
Design
-
submodule of the rest - similar on REST tools - it will be distributed on demand/dependency handling - do not rely on any specific implementation of JAX-RS 2.0 - let the programmers to use whatever library they want (i.e. Jersey, RestEasy, etc.)
- since we use RESTEasy - provide a RESTEasy client with some specific features such as client proxy framework
- use observation mechanism to register different clients for different integrations
Not covered
- error handling
- caching
- additional client implementation
Next steps
- RestWorkbench implementation
- evaluate implementation on WebSphere Commerce and Cumulus
- based on the finding from the two suggest and implement further improvements
Related stuff
Magnolia and Hybris integration - just an experiment
Proposed implementation
Diagram
Description of interfaces/classes in the diagram
| Class/Interface | Location | Description |
|---|---|---|
| RestClient | info.magnolia.rest.client | By implementing this interface, you can create your own rest client. |
| RestClientDefinition | info.magnolia.rest.client | Base interface for client definition. |
| ClientFactory | info.magnolia.rest.client.factory | By implementing this interface, you can create a client factory and set up RestClient. |
| ClientProxyDefinition | info.magnolia.rest.client.proxy | RestEasy client specific - allows you to configure and use proxies, see documentation. |
| AbstractRestCall | info.magnolia.rest.client.call | Base abstract class for all REST calls (GET, POST, PUT, HEAD, DELETE). Response is mapped to the instance of entity class which you need to set. |
Usage example
Definition of rest calls by configuration
@Inject
public MyCustomModel(RestClientRegistry restClientRegistry) {
this.restClientRegistry = restClientRegistry;
}
public ObjectNode findTopCategories() throws Exception {
return restClientRegistry.getRestClient("exampleStore").invoke("findTopCategories");
}
Using a client proxy framework (RestEasy only)
public interface CategoryService {
@GET
@Path("/{storeId}/topcategories")
@Produces("application/json")
public ObjectNode findTopCategories(@PathParam("storeId") int storeId);
}
..
CategoryService service = ((RestEasyClient) restClientRegistry.getRestClient("exampleStore")).getProxy(CategoryService.class);
ObjectNode node = service.findTopCategories(10000);
Current status
- basic implementation done
Overview
Content Tools


17 Comments
Antti Hietala
Jarda, how does this client differ from the Swagger API Explorer that ships with the REST modules. Would maybe help to add a few words to explain the difference. Thanks!
Jaroslav Simak
This client will allow you to communicate with other systems (that exposes its REST APIs) by code from Magnolia. Swagger API is documentation tool that documents REST endpoints and allows you to test these endpoints via a tool (app) - or at least thats how i understood what Swagger does.
Jan Haderka
Swagger is for exploring our REST API and emulating calls against Magnolia. This client is about turing external REST API calls to provide functions inside of Magnolia, e.g. showing components with content retrieved via REST from outside, configuring workbench to browse content on external server via REST, etc.
Tobias Mattsson
Will this be usable in a non-magnolia project? I.e a simple jar with dependencies on only JAX-RS and possibly an implementation of JAX-RS ?
Jan Haderka
Imho main benefit is the actuall integration with Magnolia. There's number of different client implementations on the net that can be used w/o. Here we try to make it very simple to plug in anything that exposes REST API into Magnolia and use it just as if it was native content. So somehow I'm failing to see how would it be useful (better then what is already available) outside of Magnolia?
Tobias Mattsson
I see, misunderstanding from my side. Ignore.
Tobias Mattsson
Its important that the client uses session cookies to avoid authenticating each call. We're using bcrypt which intentionally takes a long time to verify a password. It takes around 200 ms on my machine so authenticating each time means only 5 calls per second can be handled per core.
Jan Haderka
Why is our bcrypt use issue here? We are authenticating against external service providing REST not against Magnolia REST ... but I agree that the external authentication will be adding considerable overhead and repeated authentication should be avoided.
Tobias Mattsson
I was thinking about magnolia<->magnolia rest calls, if that's not intended then its obviously not an issue.
Magnolia International
Is there any specific reason (shared code?) that this needs to be a submodule of the rest(-server) module ? I don't have strong feelings about it, but it seems like it'd help distinguishing the two if they were actually separate codebases.
Jaroslav Simak
No, there is no specific reason for that. I just had a feeling that it might be convenient to have all rest things in one place.
If we separate things, we could then go for something like this:
which seems more clean and logical.
Magnolia International
agreed, although i'm sure there is any benefit into supporting and maintaining implementations using different libraries.
Magnolia International
How do you handle authentication ? In my POCs so far I always had a user/pass which was configured in the repo (or hardcoded when in a hurry
) which is evidently not the most secure thing to do.
Also keep in mind that for some cases we'll want a "shared" user (e.g "Magnolia" access the remote server), in some other cases we'll want some form of delegation (oauth or other, where Magnolia access the remote server on behalf of, typically, the currently logged in user)
Jaroslav Simak
I was not completely sure how to store user credentials. Leaving a password visible in the configuration tree is not an option and i wasn't able to figure out how/where to store it yet.
Maybe it would be convenient to have some sort of a authentication service/filter which anyone could implement themselves (we would only cover some basic things) and then they would just configure it in the definition?
Magnolia International
Re: exception handling, you can have a look at what i did in "my" rest client
these are 2 slightly different copies of the same idea. essentially, type the exception the client can throw, and pass them through an abstract method. Apart from that, we'll pbly want to figure out what kind of exceptions we deal with and categorize them (which do we pass black to the client, which we don't, etc, ... but that can be done at a later stage with concrete examples)
Magnolia International
Re: authentication, you suggested to keep it "up for implementation", which is good, and we'll probably want to have some working implementations
- user/pass, some people might be ok with having that in the config. some services just use plain http auth on every call
- same, but the service has a "login" endpoint, after which you have a token that you pass around on every call (again, depending on the service, the token can be a cookie, a request header, or a request param)
- keys (keys are exchanged in advance through humans, similar to ssh keys, and only those with correct key can access service)
- oauth (which takes the above a bit further); https://www.google.com/search?q=rest%20oauth&gws_rd=ssl
These are probably interesting to read:
http://www.devx.com/webdev/create-your-own-rest-api-using-oauth-authentication.html
http://stackoverflow.com/questions/4574868/securing-my-rest-api-with-oauth-while-still-allowing-authentication-via-third-pa...
Karel de Witte
If it might help I implemented this https://git.magnolia-cms.com/gitweb/?p=forge/google-analytics-demo.git;a=blob;f=src/main/java/info/magnolia/analyticsdemo/AnalyticsClient.java;h=9012e164eabb87a6d6ce5d375dde4d02ebf4ad71;hb=HEAD
AnalyticsClient it uses oauth for authentification and has a very basic implementation for decoupling http calls from ui, I use a Queue for registering the http requests using a requestId, the scheduler pops them out of the queue executes them and puts them in a results hashmap.
The key in the results hashmap is the requestId. The whole client is a singleton. Authentication is refreshed using the scheduler. So as the GA calls, so they can be smoothened, prioritized etc...
The requestId is passed as value in the httpheader so a layer 7 hardware appliance could implement some other strategy on it.
I strongly believe having Magnolia as identity provider is good for testing and development purposes, but I think that for production usages people will delegate this to a more specialized service or layer, and see Magnolia only as service provider.