The first two articles seem to be outdated respective I’m not sure if this is still the way to go. The Headless topic link proposes to use a GraphQL package.
I would like to keep it simple as possible and just write some Fusion/AFX script which would output the current node data, e.g. at /site/my-page called with /de/my-page.json as JSON output.
Is there any good example or tutorial or advices on how to do that with Fusion/AFX? For some pointes I would be glad, thanks!
You can start by adding a new condition to the Fusion root case of Neos, where it decides what to render.
Similar to how the Neos.SEO package registers its sitemap rendering.
And again similar to the sitemap you define a custom renderer with the matching Content-Type that retrieves data from your current document. At the end you have to add a process that will JSON stringify your data.
Thanks @sebobo this helps. I’m still quite a Newbie that’s why the question. I will check the Neos.SEO package and try it out. If you still have some “Newbie-Tutorial” according this topic would be great. Else I could add then a new on to the offical Neos docs if I achieve it :).
Thanks @Kollos for your hint, this was also an idea. But we really want to use Neos strength of its content-hierarichal-centric approach, so instead of rendering the page’s content as html we simply want to render it in json. That’s why we think using Fusion/AFX could be a straight-forward fit for this use-case.
The root matcher used to start rendering in Neos
The default is to use a render path of “page”, unless the requested format is not “html”
in which case the format string will be used as the render path (with dots replaced by slashes)
so by defining a fusion path /json it should already work right?.. but i would extend the root like:
Im not sure but i think you still need to configure a new route with ‘@format’: json - The question would be how to handle the root node - does this work: https://my-neos.de/.json ?
For example I would like to request /de/some-page/my-page.json and this should render then the data (properties and content child-nodes) of this requested node.
I could manage to output a first json thanks to @sebobo tipps.
I still needed to add the following to my Site Settings.yaml:
mvc:
routes:
'My.Site':
position: 'before Neos.Neos'
'Neos.Neos':
variables:
# We prefer URLs without the ".html" suffix
defaultUriSuffix: ''
else I could only render /.json or /de.json, but NOT /de/some-page/my-page.json. With the config above I could also render a json view for /de/some-page/my-page.json.
@sebobo I don’t understand yet, why the Fusion code is called by calling some-page.json? What is the connnection between this Fusion code “json = …” and the Routes definition? Is it because we define this “json = …” property that Neos knows to render it as json?
Next I try to get the right json data out of the ContentCollection nodes, etc.
Currently my challenge is that I would like to render my ContentCollection node “main” but not as html string, but as structured data. So I’m thinking of somehow to define for each content element (e.g. Button, Headline, Text&Image, Sliders, etc.) some “Json Fusion view” and so I could iterate over these content elements with their Json views. Maybe @sebobo you have also some idea how to solve this .
With this approach it is very simple to add some JSON view for some page or content element. And if there is no json view for some content element it simply renders a DefaultView.
i know that most times an explicit json view is the best, but i couldnt resist creating an automatic way ^^
you can put the following fusion code in the case after it checks for ${q(documentNode).property('_nodeType.name') + '.Json'}
if no .Json prototype is specified and the html renderer prototype uses a Neos.Fusion:Component or any inherited version (Neos.Neos:ContentComponent) this code will use the props of your html component and render it as an array:
# generate an array by using all the available props from your normal html rendering.
generatedJsonView {
# get the php implementation class, that was specified via:
# prototype(Neos.Fusion:Component).@class = 'Neos\\Fusion\\FusionObjects\\ComponentImplementation'
fusionObjectPhpImplementation = Neos.Fusion:Renderer {
renderPath = ${"/element<" + q(node).property('_nodeType.name') + ">/__meta/class"}
}
# check if the Fusion object of the current node uses a Neos.Fusion:Component (or something inherited like Neos.Neos:ContentComponent)
# if so, we can rely that there is a renderer Path and props in the context
condition = ${this.fusionObjectPhpImplementation == 'Neos\\Fusion\\FusionObjects\\ComponentImplementation' ? true : false}
type = ${q(node).property('_nodeType.name')}
# element is referring to the prototype from 'type'
element {
renderer >
renderer = Neos.Fusion:DataStructure {
nodeId = ${node.identifier}
nodeType = ${q(node).property('_nodeType.name')}
@apply.props = ${props}
}
}
}