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

The following page describes five examples of configuring and using REST clients that are leveraging the possibilities of version 2 of the REST Client module:

  • A simple configuration used
    • On a web page.
    • In a content app ((warning) requires the DX Core Edition of Magnolia).
  • Configuration with the basic security scheme.
  • Configuration with an integration of a JavaScript model.
  • Configuration using an OpenAPI schema. 

The examples are based on the declarative-rest-demo light module, a sub folder of the REST Client module in our Bitbucket repository.

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

Prerequisite: A Magnolia setup

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 on it.
  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 client configuration

In this case, a REST client is configured to send a request to the /all path of the https://restcountries.eu/rest/v2 endpoint to get a list of countries. The list is then rendered in two ways:

A) List of items on a web page.B) List of options in a content app.

The configuration of the REST client is common for both of the variants. The client is called countries, a name derived from the configuration file's name. The REST call is named allCountries.

<your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/restClients/countries.yaml
baseUrl: https://restcountries.eu/rest/v2/
restCalls:
  allCountries:
    method: GET
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: /all
    

A) Used for a web page

To render the countries as a list on a web page, you need to add the following files to the declarative-rest-demo light-module:

  • Page template definition

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/pages/rest-examples.yaml
    title: Rest Examples
    templateScript: /declarative-rest-demo/templates/pages/rest-examples.ftl
    renderType: freemarker
    
    areas:
      main:
        availableComponents:
          allCountries:
            id: declarative-rest-demo:components/countries/allCountries
    

    Note that the declarative-rest-demo light module already contains a page template definition called basic.yaml, which you could also adapt and use instead of  rest-examples.yaml.

  • Page template script

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/pages/rest-examples.ftl
    [@cms.page /]
    <!DOCTYPE html>
    <html>
      <body>
          <h1>Rest Examples Page</h1>
          [@cms.area name="main"/]
      </body>
    </html>
    

    After adding these two files, a new page template called Rest Examples should be available in the Add page dialog:


  • Component template definition

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/components/countries/allCountries.yaml
    title: List all Countries
    templateScript: /declarative-rest-demo/templates/components/countries/allCountries.ftl
    renderType: freemarker
    
  • Component template script

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/components/countries/allCountries.ftl
    [#assign countries = restfn.call("countries", "allCountries")]
    
    <h2>Countries</h2>
    
    <ul>
    [#list countries.elements() as country]
        <li>${country.get("name").textValue()}</li>
    [/#list]
    </ul>
    

    Once you have included these files in the light module, you can add the new List all Countries component to a page that is using the Rest Examples page template. (info) Since the component is the only one available in the main area of the rest-examples  page template definition, it is added to the page immediately after you click the Edit page action.

B) Used for a content app

(warning) The B variant, which renders the list in an app, works only in a DX Core Edition since it requires the REST Client UI module.

The app's content type definition is already part of the  declarative-rest-demo light module, but you have to create the apps folder in the local light module and add to the folder an app descriptor called countries.yaml from the https://git.magnolia-cms.com/projects/ENTERPRISE/repos/rest-client-ui/ repository (access to this repository is restricted). 

To see the list of countries fetched from https://restcountries.eu/rest/v2 as form select options in an app:

  1. Go to the Applauncher.
  2. In the Edit group, open the Countries (select) app:
  3. Click Add country.
  4. Click at the Name field. A pulldown list opens with country names as select options.
  5. Choose a country, for example American Samoa, and click Save. The country is then shown in the List of stored countries:

The country is also saved locally in the countries workspace, which you can check with the JCR Browser app:

The REST-relevant part of the app descriptor is shown below on lines 76-84. There, the rest datasource is configured as a JSON data source that uses the countries REST client and its allCountries REST call:For the full app descriptor, see https://git.magnolia-cms.com/projects/MODULES/repos/rest-client/browse/declarative-rest-demo/apps/countries.yaml.

Case 2: Configuration with a security scheme

This case builds on the B variant of Case 1, where the user can select a country and save it to the countries workspace.

First, check in the Definitions app that an endpoint called countries is configured on your instance: 

This is an API v2 Delivery endpoint configuration, defined in the countries.yaml file located in the <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/restEndpoints directory.

Client configuration

The REST client configuration for this use case is also pre-installed by the declarative-rest-demo. The client name is magnolia-stuff and it uses a basic security scheme configuration:

<your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/restClients/magnolia-stuff.yaml
# The local url of your Magnolia author instance rest endpoint
baseUrl: http://localhost:8080/magnoliaAuthor/.rest
securitySchemes:
  basic:
    $type: basic
    username: superuser
    password: superuser
restCalls:
  countries:
    method: GET
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: /countries
    securityScheme: basic
Page component

The component that renders the country names fetched from the local countries workspace has a template definition called countries.yaml and a template script called countries.ftl:

  • Component template definition

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/countries/countries.yaml
    title: List all Countries (magnolia repository)
    templateScript: /declarative-rest-demo/templates/components/countries/countries.ftl
    renderType: freemarker
    

  • Component template script

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/countries/countries.ftl
    [#assign countries = restfn.call("magnolia-stuff", "countries") /]
    
    <h2>Saved countries</h2>
    [#if countries?has_content]
        [#if countries?is_hash_ex]
            [#list countries.get("results").elements() as country]
                <h3>${country.get("jcrName").textValue()}</h3>
            [/#list]
        [#else]
            <h4>No country was saved in the system.</h4>
        [/#if]
    [/#if]
    
    

To make the component available in the Rest Examples page, append lines 10 and 11 shown below to the page template:

<your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/pages/rest-examples.yaml
title: Rest Examples
templateScript: /declarative-rest-demo/templates/pages/rest-examples.ftl
renderType: freemarker

areas:
  main:
    availableComponents:
      allCountries:
        id: declarative-rest-demo:components/countries/allCountries
      countries:
        id: declarative-rest-demo:components/countries/countries

You can then add the component to a page by choosing List all Countries (magnolia repository) from the list of options in the Add component dialog:

After adding the component to the page, it displays country names stored in the countries workspace:

Case 3: Configuration used together 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 an ISBN 13 number. The component template script then renders the book's title, cover image and number of pages.

Note: For this example to work, you need to expose the restClientFactory and restClientRegistry components in the configuration of the JavaScript Models module. You can do so by importing the config.modules.javascript-models.config.yaml configuration file to /modules/javascript-models.

  • Client configuration

    <your-Magnolia-installation-folder>/light-modules/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 <form/> element.


  • Component template definition

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/components/books.yaml
    title: Book Search
    templateScript: /declarative-rest-demo/templates/components/books/books.ftl
    renderType: freemarker
    modelClass: info.magnolia.module.jsmodels.rendering.JavascriptRenderingModel
    

  • Component template script

    <your-Magnolia-installation-folder>/light-modules/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

    <your-Magnolia-installation-folder>/light-modules/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();
    

To make the books component available for the Rest Examples page, append lines 12 and 13 to the page template definition:

<your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/pages/rest-examples.yaml
title: Rest Examples
templateScript: /declarative-rest-demo/templates/pages/rest-examples.ftl
renderType: freemarker

areas:
  main:
    availableComponents:
      allCountries:
        id: declarative-rest-demo:components/countries/allCountries
      countries:
        id: declarative-rest-demo:components/countries/countries
      books:
        id: declarative-rest-demo:components/books/books

You can then add the component to a page by choosing the Book Search option in the Add component dialog:

The ISBN search form is functional even in the page edit mode. For example, after entering 9780261103252 in the Isbn field and pressing the Search button, the component should display the following book data:

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, and for the schemaUrl you provide a link to an existing definition (file or URL) complying with the OpenAPi v3 specification.

  • Client configuration

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/restClients/wikipedia.yaml
    class: info.magnolia.openapi.client.OpenApiRestClientDefinition
    schemaUrl: https://en.wikipedia.org/api/rest_v1/?spec

The component below uses the onThisDay operationId to target the /feed​/onthisday​/{type}​/{mm}​/{dd} endpoint path of the Wikipedia API. 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.

  • Component template definition

    <your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/components/wiki/onthisday.yaml
    title: On this Day in the Past
    templateScript: /declarative-rest-demo/templates/components/wiki/onthisday.ftl
    renderType: freemarker

  • Component template script

    <your-Magnolia-installation-folder>/light-modules/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"]}) ]
    
    <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})
    </p>
    
    [/#list]
    
    <p>(Source: en.wikipedia.org)</p>
    Line 2: 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.
    Line 9: 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.

To make the onthisday component available for the Rest Examples page, append lines 14 and 15 to the page template definition:

<your-Magnolia-installation-folder>/light-modules/declarative-rest-demo/templates/pages/rest-examples.yaml
title: Rest Examples
templateScript: /declarative-rest-demo/templates/pages/rest-examples.ftl
renderType: freemarker

areas:
  main:
    availableComponents:
      allCountries:
        id: declarative-rest-demo:components/countries/allCountries
      countries:
        id: declarative-rest-demo:components/countries/countries
      books:
        id: declarative-rest-demo:components/books/books
      onthisday:
        id: declarative-rest-demo:components/wiki/onthisday

After this, you can add the component to a page built on the Rest Examples page template by choosing the On this Day in the Past option in the Add component dialog.

Then, in the page edit mode, a list of notable events for the current day is displayed immediately:

See also

  • No labels