How can render single content node with fusion

Hi, i have create a JSON View with fusion Case like this

root {
	default {
		type = ${q(node).property('_nodeType') + '.Document'}
		renderPath >
	}

	jsonApi {
		condition = ${request.format == 'json'}
		type = ${q(node).property('_nodeType') + '.Json'}
		renderPath >
	}
}

and Routes.yml

-
  name: 'JSON view'
  uriPattern: '{node}.json'
  defaults:
    '@package': Neos.Neos
    '@controller': Frontend\Node
    '@action': show
    '@format': json
  routeParts:
    node:
      handler: Neos\Neos\Routing\FrontendNodeRoutePartHandlerInterface
  appendExceedingArguments: true

Question:
Is there any solution to render a single content node (Text or Content Collection) that’s stored on my page/document node with URL like:
https://neosserver/url/to/my-page.json?contentId=8f5d9554-89b3-4650-8359-34bccc0892b2
or
https://neosserver/contentApi/8f5d9554-89b3-4650-8359-34bccc0892b2

The front end node route part handler uses document nodes to render a path. Using a standard flow route part handler should work but will result in the node identifier in the url.

@mficzel
Hallo Martin, this sounds like good.
But, how can I define or use a standard flow route part handler to render single content nodes?
Is there any examples for this?

MFG Mario

No example at hand sorry, but the following steps should work.

  1. Create a custom controller to render the node. Set the defaultViewClass to the className of the FusionView from the fusion Package.

  2. Implement the fusion rendering in the path fusionPath Package.Controller.Action which is triggered from the fusion view.

  3. Define a route to this controller

  4. Add policy to make this controlleraction publicly available.

The frontend node controller and route part handler expect to render documents so you cannot use them.

Hallo, thanks for your reply.

I find two workarounds for my problem.

  1. Create a custom Controller

  2. Render the node with Fusion (Neos Case and request Object)

     root {
        default {
     	#Documents as HTML
     	type = ${q(node).property('_nodeType') + '.Document'}
     	renderPath >
        }
    
     jsonApi {
     	condition = ${request.format == 'json'}
            renderer = Neos.Fusion:Case {
            if  {
     	    #Content as JSON Output
                 condition = ${!String.isBlank(request.httpRequest.arguments.contentIdentifier) && q(documentNode).find('#' + request.httpRequest.arguments.contentIdentifier).count() > 0}
                 renderer = Neos.Fusion:Http.Message {
                     httpResponseHead {
                         headers = Neos.Fusion:RawArray {
                             Content-Type = 'application/json'
                         }
                     }
    
                 output = Neos.Fusion:DataStructure {
                     #a9b9ee52-b446-49a8-89a3-6da4b800e04a
                     @context.contentNode =  ${q(documentNode).find('#' + request.httpRequest.arguments.contentIdentifier).get(0)}
                     title = ${q(contentNode).property('title')}
                     text = ${q(contentNode).property('text')}
                     _nodeType = ${q(contentNode).property('_nodeType.name')}
                     itemCount = ${q(contentNode).children('sliderItems').children('[instanceof My.Packages:ImageHeader]').count()}
                     slideItems = Neos.Fusion:Map {
    
                         items =  ${q(contentNode).children('sliderItems').children('[instanceof My.Packages:ImageHeader]')}
                         itemName = 'item'
                         itemRenderer = Neos.Fusion:DataStructure {
                             headline = ${q(item).property('headline')}
                             subHeadline = ${q(item).property('subHeadline')}
                             headlineAlign = ${q(item).property('headlineAlign')}
                             link = Neos.Neos:ConvertUris {
                                 value = ${q(item).property('link')}
                                 format = 'html'
                                 absolute = 1
                             }
                             image = Neos.Neos:ImageUri {
                                 asset = ${q(item).property('image')}
                             }
                         }
                     }
    
                 }
    
                 output.@process.renderAsJSON = ${Json.stringify(value)}
             }
         }
         api {
     		//Documents as JSON
             condition = ${String.isBlank(request.httpRequest.arguments.contentIdentifier) == true}
             type = ${q(node).property('_nodeType') + '.Json'}
         }
         @cache {
             #mode = 'dynamic'
             mode = 'uncached'
             context {
                 1 = 'node'
                 2 = 'documentNode'
             }
         }
     }
    renderPath >
         }
     }
    

Any Improvments for my all in one example?

Ahh, that is a clever trick.

You are passing the content-node as additional argument. That way you actually can use the existing routing and the default Fusion rendering.

I see nothing wrong with your code other than i would separate this a bit more into dedicated prototypes. But this is only personal preference.

Thank you for sharing this trick. I have the feeling this will be handy.

Regards, Martin