Example REST client configurations

This page presents examples of REST client definitions that leverage the possibilities of version 2 of the Magnolia REST Client module.

The examples are derived from the configurations in the declarative-rest-demo light module, a subfolder in the Magnolia rest-client repository.

As this page focuses mainly on REST client configurations, below we deal with template definitions and template scripts only marginally.

See also the Hello Magnolia - with content via REST tutorial page containing an additional and easy to configure scenario.

Prerequisite: Magnolia

To test the REST client configurations, you need:

  1. A running Magnolia instance.

    If you don’t have Magnolia installed and running, go to the page called Installing Magnolia through npm CLI and complete the steps described there.
  2. The declarative-rest-demo light module.

    You can get a copy of the light module by cloning the https://git.magnolia-cms.com/projects/MODULES/repos/rest-client/ repository and extracting the declarative-rest-demo directory to the folder defined by the magnolia.resources.dir property. If you installed Magnolia using CLI, it is the light-modules folder, located in the root of your Magnolia installation:
    <your-Magnolia-installation-folder>
    ├── apache-tomcat/
    ├── downloads/
    └── light-modules/
        └── declarative-rest-demo/

Case 1: Simple configuration

In this case, a REST client is configured to send a request to the /countries path of the https://placesapi.dev/api/v1/ endpoint to get a list of countries:

List of countries REST-generated in a component

Client configuration

The client is called countries, its name is derived from the configuration file’s name. The REST call is named allCountries in this definition.

$magnolia.resources.dir/declarative-rest-demo/restClients/countries.yaml
baseUrl: https://placesapi.dev/api/v1/
restCalls:
  allCountries:
    method: GET
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: /countries

Component template script

Example component script that renders the list of countries.

$magnolia.resources.dir/declarative-rest-demo/templates/components/countries/allCountries.ftl
[#assign response = restfn.call("countries", "allCountries")]
[#assign countries = response.get("data")]
<h2>Countries</h2>

<ul>
[#list countries.elements() as country]
    <li>${country.get("name").textValue()}</li>
[/#list]
</ul>

Case 2: Configuration with a security scheme

If the REST API service needs an authentication of a REST call, you can configure a security (authentication) scheme for it under the securitySchemes node. You can use scheme types basic and bearer, which are available out of the box in the REST client module.

For an example with the basic scheme, see basic security scheme. Below, the example configuration shows a client with the bearer scheme.

Client configuration (bearer security scheme)

Example configuration of a client called bearer-security utilizing the bearer security scheme and an expiration limit. The scheme’s configuration is defined under the bearerTokenWithExpiryDuration node, the authentication call is configured under authenticateWithDurationAsLong.

$magnolia.resources.dir/declarative-rest-demo/restClients/bearer-security.yaml
baseUrl: 'http://localhost:${wiremockPort}'
securitySchemes:
  bearerTokenWithExpiryDuration:
    class: 'info.magnolia.rest.client.authentication.definition.BearerSecuritySchemeDefinition'
    restClientName: 'bearer-security'
    restCallName: 'authenticateWithDurationAsLong'
    tokenJsonPath: '$.access_token'
    expiry:
      class: 'info.magnolia.rest.client.authentication.definition.DurationExpiryDefinition'
      expiryJsonPath: '$.expires_in'
      expiryTimeUnit: 'SECONDS'
restCalls:
  getDataWithBearer:
    method: GET
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: '/getDataWithBearer'
    securityScheme: 'bearerTokenWithExpiryDuration'
  authenticateWithDurationAsLong:
    method: POST
    entityClass: 'com.fasterxml.jackson.databind.JsonNode'
    path: '/oauth2/token'
    headers:
      'Content-Type': 'application/x-www-form-urlencoded'
      'X_Test_Expiry_Type': 'DURATION_AS_LONG'

Case 3: Configuration with a JavaScript model

This case makes use of a REST client called books and a JavaScript model called search. The model invokes the configured searchByIsbn call that queries the https://openlibrary.org/dev/docs/api/read API with a request for a record of a book identified by the ISBN 13 number.

The component template script then renders the book’s title, number of pages and its cover image (if available).

image

Client configuration

$magnolia.resources.dir/declarative-rest-demo/restClients/books.yaml
baseUrl: http://openlibrary.org/api
restCalls:
  searchByIsbn:
    method: get
    entityClass: java.lang.String
    path: /volumes/brief/isbn/{isbn}.json
    defaultValues:
      isbn: 978-3-16-148410-0
The path property uses the {isbn} template, where the JavaScript model injects the value submitted by the user in the search field.

Component template script

$magnolia.resources.dir/declarative-rest-demo/templates/components/books.ftl
[#assign isbn = ctx.getParameter("isbn")!]
[#assign isSubmitted = ctx.getParameter("submit")?has_content?then(true, false)]

[#if isbn?has_content && isSubmitted]
    [#assign result = model.search(isbn)]
[/#if]

<h2>Search books by isbn13</h2>
<p>For example: 9780261103252, 9780582517349</p>

<div style="margin:10px">
    <form method="get">
        <p>
            <label for="isbn">Isbn</label>
            <input type="text" name="isbn" />
        </p>
        <input type="submit" name="submit" value="Search" />
    </form>


[#if result?has_content]
    <p>Title: ${result.title}</p>
    <p>Number of pages: ${result.number_of_pages}</p>
    <img src="${result.cover.large}" alt="Cover"/>
[/#if]
</div>

JavaScript

$magnolia.resources.dir/declarative-rest-demo/templates/components/books.js
var BookModel = function () {

    var restClient = restClientFactory.createClientIfAbsent(restClientRegistry.getProvider("books").get());

    this.search = function (isbn) {
        var result = restClient.invoke("searchByIsbn", { isbn: isbn});
        var data = JSON.parse(result.getEntity());
        if (data && data.records) {
            var keys = Object.keys(data.records);
            return data.records[keys[0]].data;
        }
        return null;
    }
};

new BookModel();

Case 4: Configuration using an OpenAPI schema

The benefit of a configuration using an OpenAPI schema is that all that is required to configure a REST client is reduced just to two properties, class and schemaUrl.

  • For the class, you use info.magnolia.openapi.client.OpenApiRestClientDefinition.

  • For the schemaUrl, you provide a link to an existing definition (file or URL) complying with the OpenAPi v3 specification.

Client configuration

$magnolia.resources.dir/declarative-rest-demo/restClients/wikipedia.yaml
class: info.magnolia.openapi.client.OpenApiRestClientDefinition
schemaUrl: https://en.wikipedia.org/api/rest_v1/?spec

Component template script

$magnolia.resources.dir/declarative-rest-demo/templates/components/wiki/onthisday.ftl
[#assign aDateTime = .now]
[#assign results = restfn.call("wikipedia", "onThisDay", {"type":"all", "mm":aDateTime?string["MM"], "dd":aDateTime?string["dd"]}) ] (1)

<h2>What happened on ${aDateTime?string["MMMM"]} ${aDateTime?string["dd"]} in the past?</h2>

[#list results.get("selected").elements() as event]

<p>
  ${event.get("text").textValue()} (${event.get("year").intValue()?c}) (2)
</p>

[/#list]

<p>(Source: en.wikipedia.org)</p>
1 The alias onThisDay is used to target the endpoint path since the alias is defined in the schema. If this weren’t the case, you can always refer to a call name using the following pattern: method:/path/pathAction.
2 At the end of the directive, the c FreeMarker builtin is used to render the intValue() for the year without formatting for human audience, for example as 2019 rather than 2,019.

After passing the template values for type, month and date, the component displays a list of notable events that happened on the given day at some point in the past, for example:

image

Feedback