While most of our partners create client websites that have no connection to other sites, this is not always the case. For example, a national football tournament would need multiple related websites for each of the participating football clubs.
The Dynamic Content Module (DCM) allows the partner to set up shared dynamic information across all these sites (assuming that they are created by the same partner), by controlling rendered content from an external source other than Mono, but updated only in a single place.
The new module can be used to build your own widgets or branded footers for partners where most of their clients have no knowledge of each other. For example, a logo can be changed with one click on all these sites in the future through the DCM.
Find the Dynamic Content Module under 'Page Layout' in the 'Add Module' overlay.
Content
In the editor, the content to be embedded on the site is chosen from the overlay level of the DCM module. The contents offered by the partner are loaded in the editor and visible on the overlay from the selectable dropdown. The upper dropdown lets you choose the category of the content, whereas the bottom dropdown lets you choose the available variations within that category.
Please note that the content will not render in the editor. Instead, it is marked with a placeholder. If you wish to see if the rendered content, you can always preview the site before publishing it. Both previewed and published sites load the module.
Design
The editor allows you for additional, basic styling to the DCM to make it more suitable for your site design.
Technical requirements/integration part
To use the Dynamic Content Module, partners need two services:
- Its own Application Program Interface (API) endpoint returning offered contents,
- and an API for content render.
The former API is the one Mono editor uses for showing available content in the overlay. Together with the names of categories and variations, it should provide the embeddable HTML content that communicates with the rendering API. Given the nature of this process, the HTML content should include a script element. Omitting this aspect prevents responsiveness of embedded content to changes on the partner-API level. If that is the case, the rendering API is also not required from the partner.
The latter (rendering) API provides a gateway to access common elements from one location. This way the integrity of style and functionality across sites is ensured. Rendered structure and style is not cached on Mono sites. Therefore, a fresh render of the custom content happens on each site visit (previewed or published) ensuring the latest version of the partner-specific content. Additional benefit is the source of requested change – since the rendering API is maintained by the partner, the change needs to be done within their system’s scope. With granted independence from external help and easy access to requested change’s origin, we provide a scalable tool with endless customization possibilities.
If the embedded content contains a script, it is executed when site loads and creates a request with appropriate parameters to the rendering API. Those should be sufficient to authenticate Mono user and site in partner’s system. The script is responsible for integrating partner-specific module on the site.
API definition notes
The response from the API providing list of available contents needs to follow specific schema to work correctly with the website editor. To identify Mono users at partner’s API level a JSON Web Token (JWT) is generated by us. The specification of fields and structures of headers, responses and tokens is given below.
1: Endpoint
The partner needs to provide an endpoint URL, where available modules can be pulled. The endpoint needs to accept GET requests and implement a caller identification based on JWT signature verification.
2: Authentication token
The authentication token is a signed JWT bearer token hashed with HS256 (HMAC with SHA-256). Salt used for hashing can be provided either by the partner or Mono. Generated bearer token is used as authentication header value - "Authentication ": "Bearer <JWT>". This is the only header we add on top of the default ones. The specification of the JWT fields and values is given below:
a: Field reference
Field name |
Data type |
Description |
iss |
string |
Issuer name. “MS” value is used as the identification of Mono. |
iat |
number |
Time when token was generated/issued. |
exp |
number |
Expiration time of the token. By default its value is calculated as follows: iat+60s |
aud |
string |
Mono site ID in Mono system. |
sub |
string |
Mono account ID in Mono system. |
b: JSON example
{
"iss": "MS",
"iat": 1678730616,
"exp": 1678731863,
"aud": "1234567",
"sub": "123456"
}
3: Successful response
If the Mono user was authenticated in a partner’s system, it should respond with one of the successful responses status codes – by default 200. The response can contain information about returned contents partitioned into pages and must contain a collection of available contents. Expected data types and values are described in detail by the end of this section.
The schema should follow the structure as below:
{
"links"?: {
"self": "example.com/page=2",
"previous": "example.com/page=1",
"next": "example.com/page=3"
},
"data": [
{
"type": "Events",
"collection": [
{
"type": "City events",
"id": "3ec3b369",
"attributes": {
"label": "Event-1",
"content": "<script src="https://example.com/subpath/executable.js"></script><div id=”placeholder-3ec3b369"></div>”
}
}
]
},
{
"type": "Slideshows",
"collection": [
{
"type": "Pretty slideshow,
"id": "0oc4d388",
"attributes": {
"label": "Slideshow-1",
"content": "<script src="https://example.com/subpath/executable.js"></script><div id=”placeholder-0oc4d388"></div>"
}
}
]
},
{
"type": "Forms",
"collection": [
{
"type": "Contact form,
"id": "1wc6y482",
"attributes": {
"label": "Form-1",
"content": "<script src="https://example.com/subpath/executable.js"></script><div id=”placeholder-1wc6y482"></div>"
}
}
]
}
]
}
4: Errored response
In case of an error on the partner’s API side, a corresponding and informative error message should be returned. It is important to use standard status codes (4xx and 5xx) for respective issues. The details of each field in error response are described by the end of this section. The schema for it is given below:
{
"error": {
"code": "BadRequest",
"message": "The requested content is missing.",
"target"?: "Pretty slideshow",
"details"?: [
{
"code": "BadRequest",
"target": "Slideshow-1",
"message": "Missing implementation of Slideshow-1 element."
}
]
}
}
5: Data fields specification
Response code |
Field path |
Data type |
Description |
200 OK |
links |
object |
Optional field indicating paginated response. |
links.self |
string |
Pagination; Current page path. | |
links.previous |
string |
Pagination; Previous page path. Empty if there is no previous page. |
|
links.next |
string |
Pagination; Next page path. Empty if there is no next page. |
|
data |
array |
Array of custom contents offered by the partner. |
|
data[0].type |
string |
Parent-category name of the content. |
|
data[0].collection |
array |
Array of contents variations. |
|
data[0].collection[0].type |
string |
Content’s variant name. |
|
data[0].collection[0].id
|
string |
UUID or Unique HASH of the content |
|
data[0].collection[0].attributes.label |
string |
Caption of the particular content variation. |
|
data[0].collection[0].attributes.content
|
string |
HTML element(s) representing particular content variation to be embedded at the site. |
|
400 BadRequest
Or any other 4xx and 5xx code. |
code |
string |
Status code meaning. Any 4xx code should reflect its corresponding meaning. 400 is the default. |
message |
string |
Descriptive message of the error. |
|
target |
string |
Optional, describes the target that originated the error. |
|
details |
array |
Optional, an array of additional, partner-specific errors. |
|
details[0].code |
string |
Status code meaning. Any 4xx code should reflect its corresponding meaning. 400 is the default. |
|
details[0].target
|
string |
Describes the target that originated the error. |
|
details[0].message
|
string |
Descriptive message of the additional error. |