Page tree
Skip to end of metadata
Go to start of metadata

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/InterfaceLocationDescription
RestClientinfo.magnolia.rest.client

By implementing this interface, you can create your own rest client.

RestClientDefinitioninfo.magnolia.rest.clientBase interface for client definition.
ClientFactoryinfo.magnolia.rest.client.factoryBy implementing this interface, you can create a client factory and set up RestClient.
ClientProxyDefinitioninfo.magnolia.rest.client.proxyRestEasy client specific - allows you to configure and use proxies, see documentation.
AbstractRestCallinfo.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
  • No labels

17 Comments

  1. 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!

    1. 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. 

    2. 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.

  2. 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 ?

    1. 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?

      1. I see, misunderstanding from my side. Ignore.

  3. 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.

    1. 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.

      1. I was thinking about magnolia<->magnolia rest calls, if that's not intended then its obviously not an issue.

  4. 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.

    1. 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:

      • rest-client base module which would not depend on any specific implementation
      • and then have implementation-specific modules like resteasy, jersey etc.

      which seems more clean and logical.

      1. agreed, although i'm sure there is any benefit into supporting and maintaining implementations using different libraries.

  5. 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(wink)) 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)

    1. 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(wink)) which is evidently not the most secure thing to do.

      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.

      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)

      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?

  6. 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)

  7. 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...


  8. 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.