This page provides an overview of the different ways of retrieving JSON
for JCR-based content in Magnolia as well as listing their respective
advantages and disadvantages.
Magnolia Delivery API
The delivery API is a Magnolia REST resource introduced with version
2.0 of the Magnolia REST modules. We recommend you use
Delivery API to benefit from all the latest features.
This REST resource is highly customizable. You can define multiple
endpoint configurations to serve different needs. Each configured
endpoint is accessed through a distinct
endpointPath
and provides two sub-resources. The sub-resources can be called with
HTTP GET both to read a node (and its subnodes) by a given path
and to query nodes.
Example: Find a tour with the word Japan in its description.
Return only the variant in the German language:
{
"results": [
{
"@name": "Kyoto",
"@path": "/magnolia-travels/Kyoto",
"@id": "b475f27e-2929-427b-9517-815118a3b36e",
"@nodeType": "mgnl:content",
"body": "<p>Erleben Sie die Schönheit, die Kyoto durchdringt und umgibt. Kyoto ist berühmt für viele Dinge, darunter unzählige <a href=\"http://www.japan-guide.com/e/e2058.html\" target=\"_blank\">Tempel</a>, <a href=\"http://www.japan-guide.com/e/e2059.html\" target=\"_blank\">Schreine</a> und andere faszinierende historische Bauwerke.</p>\n<p>Kommen Sie mit uns auf einen Besuch der Stadt der zehntausend Schreine. Wir besuchen To-ji, Ginkaku-ji, Kōzan-ji und ihre bemerkenswerten Gärten, bevor wir einen Abstecher zu den Bergen in der Umgebung der Stadt machen. Sie werden es genießen, einen Tag im grünen Miyama und einen Tag mit Wandern in Shizuhara zu verbringen. Sie werden nie wieder wie bisher über Japan denken.</p> ",
"name": "Kyoto",
"description": "Die natürliche Seite Japans",
"destination": [
"7ec72c48-c33f-418e-b2ff-44cfb4bbb1f2"
],
"location": "Kyoto, Japan",
"tourTypes": [
"d2245867-ecaa-4b4e-8743-e0c939be68b7",
"415025c6-e4b5-4506-9384-34f428a52104"
],
"author": "Magnolia Travels",
"duration": "7",
"image": "jcr:44689d29-5966-4d41-8fd4-2dc7da783528",
"@nodes": []
}
]
}Copy
This result is returned for the endpoint called ep with the following
configuration:
$type:jcrDeliveryEndpoint_v2workspace:toursCopy
Pros
Convenient and simple to use JSON structure.
Supports RESTful URLs.
Highly configurable via YAML file in a
light module or in the JCR configuration
workspace.
Supports multiple endpoint configurations to serve different needs.
@Path("/allCameras")
@GET@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get all cameras.", notes = "Returns json for the list of all a camera objects.")
@ApiResponses(value = {
@ApiResponse(code = 200, message = STATUS_MESSAGE_OK, response = List.class),
@ApiResponse(code= 401, message = STATUS_MESSAGE_UNAUTHORIZED),
@ApiResponse(code = 404, message = STATUS_MESSAGE_NODE_NOT_FOUND),
@ApiResponse(code = 500, message = STATUS_MESSAGE_ERROR_OCCURRED)
})
public List<Camera> getAllCameras(){
List<Camera> result = null;
try {
result = cameraCollectionPojoService.getAllCameras();
} catch (RepositoryException e) {
log.warn("Could not compute the list of all cameras.");
}
return result;
}Copy
To explore the complete example, clone the camera-collection module from git.
When using com.wordnik.swagger.annotations.*, endpoints are
automatically exposed in the Swagger tool for testing (see
Swagger API
explorer).
Delivery of personalized variants of pages or components is possible
(see personalization).
Cons
Requires Java skills.
Must be deployed in a Maven module.
FreeMarker template
You can implement a custom JSON provider in a FreeMarker template
script. Use
templating
functions such as
cmsfn,
damfn
and others to read data from JCR and render JSON in your preferred
manner.
Approaches: A pure JSON provider or an HTML-mixed one
Pure JSON
You can write a FreeMarker template in a way that its response is pure
JSON. This is what we consider as a template script based or FreeMarker
based JSON provider. To go for this approach, do the following:
Create a page template. A dialog is not required.
Write FreeMarker code that renders JSON.
Create a page with this new template.
Request the new page to get JSON in the response.
Step 2 can go from very simple to very complex.
Mixed with HTML
You also can write a template that renders HTML and assigns JSON to
JavaScript variables:
<!DOCTYPE html><htmlxml:lang="${cmsfn.language()}"lang="${cmsfn.language()}"><head>
[@cms.page /]
<metacharset="utf-8" />
[#assign pageNode = cmsfn.contentByPath("/magnolia-travels/Kyoto", "tours")]
<script>var someJson = '${jsonfn.from(pageNode).add("@path", "name", "description").wrapForI18n().inline().print()}';
</script></head><bodyclass="mixed ${cmsfn.language()}"><divclass="container "><h1>Find a better title later on ;-)</h1></div></body></html>Copy
See line 8 where JSON is assigned to a JavaScript variable.
Assembling JSON manually
Here is a simple example of how you can assemble JSON structure in
FreeMarker:
When assembling JSON manually, you have maximal freedom to define the
JSON structure, but this approach also requires a high coding effort.
The sample project camera-collection provides a more sophisticated FreeMarker-based JSON provider.
Assembling JSON with jsonfn
jsonfn
templating functions generate JSON from JCR nodes in any workspace.
jsonfn helps you assemble JSON within a FreeMaker template script and
provides powerful methods to generate JSON in a flexible way. It can
resolve references to nodes of other workspaces and it also provides
links to renditions of assets in one request. See
resolving
referenced nodes and renditions.
To achieve the same JSON as in Assembling JSON manually above, write
the following code:
jsonfn templating functions are not bundled with preconfigured
Magnolia bundles or webapps.
Setting the proper content type of the response
If your FreeMarker template acts as a pure JSON provider, you may want
to set the content type of the response to application/json. You
cannot set the content type directly in the
template definition. Instead you
have to define a new renderer and reference this renderer in the
template definition with the renderType property.
However, having the proper content type may not be required. In many
use cases it is sufficient to use the FreeMarker renderType that
responds with text/html.
Turning a template-based JSON provider into a RESTful API with virtualURIMapping
You can create a template that accepts request parameters to specify the
JSON content to be returned. In the example below, you can specify the
workspace and the path of the node.
Delivery of personalized variants of pages or components is possible
(see personalization).
Cons
Security cannot be set per workspace and path, but only generally for
the page that acts as the JSON provider.
Methods beyond GET (such as PUT, POST or DELETE) cannot be
implemented using just FreeMarker.
Getting localized JSON
If your content is localized, you can also get localized JSON output.
See enabling
multi-language content about how to create localized content.
Depending on the technique applied to get JSON, you may have to force
getting the localized version or you will get a JSON version of the
default locale.
With the delivery API
With the
Delivery API, you can configure multiple endpoints with full content
localization support.
To request a specific single language variant, do one of the following:
Set the Accept-Language header. For example: Accept-Language: de-DE
Set the lang`query parameter. For example: `lang=de-DE
If both are set, the lang parameter takes priority. If neither is set, the decision is delegated to the I18nContentSupport interface.
To return all language variants:
Set the lang query parameter to all: lang=all
You can use both the Accept-Language header and the lang query parameter for both sub-resources Read node and Query nodes.
Localized properties must be read as <property-name>_<LOCALE>. For
example, description_de for the property named description. The
default endpoints do not take the client’s locale into account. When
JSON is generated, the nodes are not wrapped with
info.magnolia.jcr.wrapper.I18nNodeWrapper. It is
impossible to tell which language is default.
With custom JAVA endpoints
In a custom endpoint, you typically fetch javax.jcr.Node
objects (Java objects representing JCR nodes) that you transform into
JSON later on. Make sure you wrap the node with
info.magnolia.jcr.wrapper.I18nNodeWrapper before
producing JSON. The following shows a method wrapping a node to make
sure it is localized (copied from
info.magnolia.templating.functions.TemplatingFunctions,
which is the underlying Java class of cmsfn):
public Node wrapForI18n(Node content){
return content != null?new I18nNodeWrapper(content):null;
}Copy
Here the I18nNodeWrapper causes the values to be returned in their
localized form.
In a FreeMarker template
In a FreeMarker template, it is the wrapForI18n method that makes sure
the values are returned in their localized form.
With manually assembled JSON
Use cmsfn.wrapForI18n to get a localized version of a content node:
Therefore, if your application resides within a domain that is different
from the domain that hosts your data, the web browser will actively
prevent accessing content stored under the host domain.
An elegant solution to solve the same-origin policy without changing
Apache configuration is the Magnolia
Add
HTTP Headers filter. This filter is available out-of-the-box; you only
need to configure it.