Example REST client configurations

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

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.

Case 1: Simple configuration

In this case, a REST client is configured to send a request to the /wonders path of the https://www.world-wonders-api.org/v0/ endpoint to get a list of selected wonders of the world.

Client configuration

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

$magnolia.resources.dir/declarative-rest-demo/restClients/wonders.yaml
baseUrl: https://www.world-wonders-api.org/v0/
restCalls:
  allWonders:
    method: GET
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: /wonders

Component template script

Example component script that renders the list of wonders.

$magnolia.resources.dir/declarative-rest-demo/templates/components/wonders/allWonders.ftl
[#assign response = restfn.call("wonders", "allWonders")]

<h2>Wonders</h2>

<ul>
[#list response.elements() as wonder]
    <li>${wonder.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 are more example configurations.

Bearer token with expiry duration

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:
    $type: bearer
    restClientName: bearer-security
    restCallName: authenticateWithDurationAsLong
    tokenJsonPath: $.access_token
    expiry:
      $type: duration
      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

OAuth2 bearer security scheme with expiry duration

Example configuration of a client called knowledgeSource also utilizing the bearer security scheme and an expiration limit. The scheme’s configuration is defined under the oauth2 node. The authentication call is configured under authenticate in a separate knowledgeSourceAuth.yaml configuration file.

This example showcases a situation in which you are using a third-party authentication service for your REST calls. In other words, the authentication URL is different from the service URL.

In this particular example configuration, the domain where the token is served from is example.net while the REST service is hosted on example.com.

$magnolia.resources.dir/rest-demo/restClients/knowledgeSource.yaml
baseUrl: https://api.example.com/systems/client/v1
securitySchemes:
  oauth2:
    $type: bearer
    restClientName: knowledgeSourceAuth
    restCallName: authenticate
    tokenJsonPath: $.access_token
    expiry:
      $type: duration
      expiryJsonPath: $.expires_in
      expiryTimeUnit: SECONDS
restCalls:
  getUser:
    method: get
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: /users/123
    securityScheme: oauth2
  getUsersInOrg:
    method: get
    entityClass: com.fasterxml.jackson.databind.JsonNode
    path: /organisations/abc-123/users
    securityScheme: oauth2
$magnolia.resources.dir/rest-demo/restClients/knowledgeSourceAuth.yaml
baseUrl: https://login.example.net/089a6470-d3a7-46a4-8852-74c0c698c729
restCalls:
  authenticate:
    headers:
      Content-Type: "application/x-www-form-urlencoded"
    path: /oauth2/v2.0/token
    method: post
    entityClass: com.fasterxml.jackson.databind.JsonNode
    body: 'client_id=62336501-fbe2-4fbe-9bba-1b0b4a8c8573&client_secret=Sih8Q~tW-Sdnxc4tdvECHfwYGIJ6jaP4TeKfzcVr&grant_type=client_credentials&scope=https%3A%2F%2Fapi.app.example.com%2Fsgc%2F.default'

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

Book search results

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:

On this day in the past

Feedback

DX Core

×

Location

This widget lets you know where you are on the docs site.

You are currently perusing through the DX Core docs.

Main doc sections

DX Core Headless PaaS Legacy Cloud Incubator modules