Magnolia REST client module enables easy creation, configuration and usage of REST clients. All it takes is a few clicks and a few bits of Java code. The module:

  • Uses  RESTEasy.
  • Provides an app to test clients.
  • Includes restfn templating functions that give access to REST clients within FreeMarker template scripts.

You also can obtain a REST client within Java to build apps, custom fields for dialogs and similar things.

This page describes the module, explains how to install it and gives a quick reference how to declare, configure and use REST clients.

Installing

Maven is the easiest way to install the module. Add the following to your bundle:

Error rendering macro 'artifact-maven-dependencies-snippet-macro'

com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found


Due to Maven transient dependencies, adding magnolia-rest-client-app to your bundle automatically adds the magnolia-rest-client and magnolia-resteasy-client modules.

Pre-built JARs are also available for download. See Installing a module for help.

  • Error rendering macro 'artifact-resource-macro'

    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

  • Error rendering macro 'artifact-resource-macro'

    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

  • Error rendering macro 'artifact-resource-macro'

    com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and Java type class info.magnolia.sys.confluence.plugin.artifactinfo.nexus.entities.SearchNGResponse, and MIME media type application/octet-stream was not found

Add all the submodules to your bundle.

All preconfigured Magnolia bundles (besides magnolia-empty-webapp) contain magnolia-resteasy-client but not magnolia-rest-client-app.

Submodules

  • magnolia-resteasy-client:  The easy-to-use Magnolia REST client implementation. It enables interface based service declaration. The module has a dependency to RESTEasy from JBoss.
  • magnolia-rest-client-app: Installs an app to test REST clients in the browser. You can test your clients in the app before using them in template scripts, models or other Java classes. See Testing clients in the REST client app
  • magnolia-rest-client: Defines the API for a Magnolia REST client definition class (to configure), for a REST client factory (to create instances) and for a registry (to obtain configured clients). It is an abstract layer which, besides the registry, you will hardly ever use directly. If you have existing Java clients based on jersey or raw javax.ws.rs, you can implement a custom ClientFactory to instantiate your existing custom clients the Magnolia way. 

Overview and summary about how to enable a Java client in Magnolia

  1. Create a service interface.

  2. Configure the the client.
  3. Test the client in the Rest Client app

Service interface declaration

When working with a RestEasy client, a service must be declared as a Java interface using javax.ws.rs annotations.

Note that a Java interface must be part of a Magnolia Maven module, it is not possible to have Java classes or interfaces within a pure file-based module (light module).

  Example: Declaring an interface to get a client that requests the URL  http://api.icndb.com/jokes/random?firstName=John&lastName=Doe.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
 
public interface IcndbService {  
  @GET
  @Path("/jokes/{select}")
  @Produces(MediaType.APPLICATION_JSON)
  JsonNode joke(@PathParam("select") String select, @QueryParam("firstName") String firstName, @QueryParam("lastName") String lastName);
}
  • The return type of a method and the @Produces declaration must correspond. In the example above the method #joke will return a org.codehaus.jackson.JsonNode object - this fits well together with @Produces(MediaType.APPLICATION_JSON).
  • The value of the @Path annotation is relative to the baseUrl of this java client. In this example the relative URL starts with /jokes followed by a parameter. The baseUrl itself is defined in the configuration.
  • Create a method for each sub-resource / parameters combination which you will need.

Configuration

You can configure REST clients within all Magnolia modules in the rest-client folder.

Example: REST client configuration

Node nameValue

 
modules


 
<your-module>


 
rest-client


 
icndbClient


 
baseUrl

http://api.icndb.com

 
class

info.magnolia.resteasy.client.RestEasyClientDefinition

 
clientFactoryClass

info.magnolia.resteasy.client.factory.RestEasyClientFactory

 
components


 
authentication


 
class

org.example.filters.AuthenticationInterceptor

Properties:

<rest client name>

required

Add a node for each REST client. The name is arbitrary, but it is good practice to use a descriptive name. The node name is used when obtaining instances of clients.

baseUrl

required

The base URL of the REST endpoint to connect with the client.

class

required

The definition class, it must implement RestClientDefinition, for instance use RestEasyClientDefinition or SSLRestEasyClientDefinition for secure connections or subclasses.

If you rely on components or clientFilters, the definition class must extend RestEasyClientDefinition.

clientFactoryClass

required

The client factory class. Must implement ClientFactory. Use RestEasyClientFactory or SSLRestEasyClientFactory for secure connections or subclasses.

cachable

optionaldefault is true

Enables the underlying caching mechanism provided by RESTEasy.

components

optional

1.0.8+

A list of components (e.g. ClientRequestFilter, ClientResponseFilter). Registered components will be executed on every request.

clientFilters

optional

(warning) deprecated since 1.0.8, use components instead

 A list of components (e.g. ClientRequestFilter, ClientResponseFilter).

proxyDefinitions

optional

A map of ClientServiceDefinition objects.

Please note that ClientErrorInterceptor is not supported since Magnolia 5.6.

Testing clients in the Rest Client app

You need to configure and declare RESTEasy clients before you can test them in the app.

To test a client:

  1. Open the Rest Client app (DEV group).
  2. Rest client: Select a client.
  3. Rest services: Add the fully qualified class name of the service interface, for example. info.magnolia.documentation.modules.restclientexamples.client.IcndbService, and click Confirm
  4. Service method: Select the method to be executed on the given client. Example IcndbService  has 3 methods.
  5. Method parameters: Provide the parameters for the selected method. The app prompts by providing method annotations. 
  6. Click Send request.
  7. Response: The response displays.

Getting and using client instances

restfn templating functions

restfn templating functions allow you obtain and use REST clients.This works only for clients that have been configured and declared with RESTEasy client.

Example:

[#assign jokesService = restfn.getService("icndbClient", "info.magnolia.documentation.modules.restclientexamples.client.IcndbService")]
[#assign response = jokesService.joke("random", "Tiger", "Lilly") /]
<i>${response.get("value").get("joke").getTextValue()!"Nix found"}</i>
  • Line 1 accesses an instance of the client interface. In this example it is of type IcndbService
    • First parameter is the name of the client configuration node (icndbClient), 
    • Second parameter is the fully qualified class name of the declared service interface (info.magnolia.documentation.modules.restclientexamples.client.IcndbService).
  • Line 2 calls the method #joke which returns a JsonNode object.
  • Note that is a simplified example. See jackson javadoc how to further process the JsonNode or assign a raw response to a JavaScript variable to process JSON in a JavaScript context.

    <script>
        var jokeJson = '${jokesService.joke("random", "Tiger", "Lilly")!}';
    </script>

During installation of the magnolia-resteasy-client module, RestEasyClientModuleVersionHandler adds restfn to renderer configurations. Make sure that the renderType of your template definition points to a renderer that is configured to use restfn. See Configure the functions in a renderer on how to add templating functions to a renderer.

Java using client registry

To explain how to obtain and use REST client, we look at a model class which uses the same client as in the above example:

public class JokesModel<RD extends RenderableDefinition> extends RenderingModelImpl<RD> {
 
    private static final Logger log = LoggerFactory.getLogger(JokesModel.class);
 
    private final RestClientRegistry restClientRegistry;
 
    public JokesModel(Node content, RD definition, RenderingModel<?> parent, RestClientRegistry restClientRegistry) {
        super(content, definition, parent);
        this.restClientRegistry = restClientRegistry;
    }
 
    public String getRandomJoke() {
        String joke = "No joke! Failed to fetch it due to an error. :-(";
        RestEasyClient client = null;
        IcndbService service = null;
        try {
            client = (RestEasyClient) restClientRegistry.getRestClient("icndbClient");
            service = client.getClientService(IcndbService.class);
        } catch (RegistrationException e) {
            log.error("Failed to get a client for [icndbClient].", e);
        }
        if (service != null) {
            JsonNode response = service.joke("random", "Tiger", "Lilly");
            try {
                joke = response.get("value").get("joke").getTextValue();
            } catch (Exception e) {
                log.error("Failed to fetch the joke when parsing response.", e);
            }
        }
        return joke;
    }
}

  • Add RestClientRegistry as parameter into the constructor and assign it as final instance variable (See lines 5, 7, 9.)
  • Obtain RestEasyClient object from the RestClientRegistry. Note that #getRestClient requires the configured name of the rest client definition. (See line 17.)
  • Create an instance of the declared interface IcndbService. (See line 18.)
  • Now call the declared method(s) on the service (line 23).

Component example

You have the option to configure components (filters) to be executed on every request. One use case could be authentication.

Client Request Filter

Here is a sample filter that would handle authorization for each request. 

AuthenticationInterceptor
package org.example.filters;

import info.magnolia.context.Context;
import info.magnolia.context.MgnlContext;
import java.io.IOException;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.ext.Provider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Interceptor for rest easy to handle authentication with an access token.
 */
@Provider
public class AuthenticationInterceptor implements ClientRequestFilter {
    
    private static final Logger log = LoggerFactory.getLogger(AuthenticationInterceptor.class);
    
    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        if (MgnlContext.hasInstance() && MgnlContext.hasAttribute("ACCESS_TOKEN", Context.APPLICATION_SCOPE)) {
            requestContext.getHeaders().putSingle("Authorization", 
				"OAuth " + MgnlContext.getAttribute("ACCESS_TOKEN", Context.APPLICATION_SCOPE));

            log.trace("Authorization : {}", 
				(String) MgnlContext.getAttribute("ACCESS_TOKEN", Context.APPLICATION_SCOPE));
        }
    }
}

Further reading

#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))

10 Comments

  1. Hello,

    I install rest-client module, but i dont know to create client. According guide, it config by hand, but i want to config by java?

    Can you help me?


    Thanks,

    DTTHuyen

    1. I hoped that docu was quite clear.

      Overview and summary about how to enable a Java client in Magnolia
      1. Create a service interface.
      2. Configure the the client.
      3. Test the client in the Rest Client app

      I recommend to do as described here.


      But if you think you do the "configuration by Java" - as some things can be configured by Java with blossom - you can try it out. But I have no idea whether it will work and whether it is doable.

      There is a good reason to do some configuration outside of Java.

      1. yep, i am trying with blossom.

        I did step by step to guide. i got data from URI API ( http://api.icndb.com/jokes/random?firstName=John&lastName=Doe)

        But i want to import data from this api to magnolia app (ex: products), i will create api store products and i want to import it to products app.

        => So i thinks i config to import it.

        Beside, magnolia have REST APP API can GET, POST data. But i select them manual (ex POST, i create ResponseBody and paste it  and try it. But I want to import content from an external source (URI API) into a Magnolia workspace.

  2. In my project I have to manage a recruitment list. Can I get this data from an external api to add to the list? Christoph Meier


      1. Oh how i can do that :3 Can you show me the sample of how you did it

        1. Since you insist in doing things with Blossom, I recommend you to ask the community which may give you better answers than i can.
          You also have a chance there to get opinions from different people.
          We have recently moved the channel for community discussions from a forum to google groups.
          So please use one of these groups:
          - https://groups.google.com/a/magnolia-cms.com/forum/#!forum/user-list
          - https://groups.google.com/a/magnolia-cms.com/forum/#!forum/dev-list

          And there is still the possibility to get in contact with our services departement:
          https://www.magnolia-cms.com/services.html

          kind regards,
          Christoph

        2. If you do it without Blossom. Follow the instructions of this page.

          1. Sorry, I not use blossom. I create module by mvn. And if i want to custom it, I will custom by java.

            1. I dont use magnolia cli, i create webapp and create modue by mvn.