Custom route to json content representation

Iā€™m creating a route to a json template, for which there is no ā€˜realā€™ page content, so Iā€™m using a custom route. In my config:

'routes' => [
  [
    'pattern' => 'otherstuff.json',
    'action'  => function () {
      return new Page([
        'slug' => 'otherstuff',
        'template' => 'otherstuff.json',
      ]);
    }
  ]
]

Which works, in that it renders templates/otherstuff.json but as a standard html response, not as application/json.
I can get around that by including
$kirby->response()->code(200)->type('application/json'); in the template, but that doesnā€™t feel it has the usual Kirby elegance about it! i.e that route is not really content representation aware.
Is there a ā€˜properā€™ way of building a route that would work for both the default and other content representations?

Use headerā€¦ something like thisā€¦

    'action'  => function() {
      header('Content-type: application/json; charset=utf-8');
      // More stuff...
    }

Thats how i did it in Kirby 2, i think it will still fly. If it doesnt, lookup ā€œheaderā€ in the reference and see what the new syntax is.

And please also mark you thread as a kirby 3 question :slight_smile:

Thanks, yes there are a number of places/ways I can set that as a header, but that doesnā€™t really use the power of content representations as I would like to believe is possible.
For instance this more generic route will match all content representations of that slug:

 [
    'pattern' => 'otherstuff(.?[a-z]*)', //page with any .ext
    'action'  => function ($ext) {
      return new Page([
        'slug' => 'otherstuff',
        'type' => $ext, // try and set type (no effect)
        'contentType' => $ext, // try and set contentType (no effect)
        'template' => 'otherstuff'.$ext, // set template. this works
      ]);
    }
  ]

On a ā€˜realā€™ page, Kirby would automagically recognise that file extension as a content representation and set headers accordingly. That doesnā€™t work on this route. Iā€™m sure there is a way to set that in the Page object, but all my guesses have had no effect so far!

Provided that the content representation application.json.php exists, you can use the render() method like this:

    'routes' => [
        [
          'pattern' => 'otherstuff.json',
          'action'  => function () {
            $newPage = new Page([
                'slug' => 'otherstuff',
                'template' => 'otherstuff.jspn',
          
              ]);
              return $newPage->render([], 'application/json');
          }
        ]
    ]

Thank you @texnixe, that looks more like it.
Though weirdly, it still doesnā€™t seem to be setting the contentType headers.
I needed to set the template to the base representation, and the contentType to ā€˜jsonā€™ like so:

  [
    'pattern' => 'otherstuff.json',
    'action'  => function () {
      $newPage = new Page([
        'slug' => 'otherstuff',
        'template' => 'otherstuff',
      ]);
      return $newPage->render([], 'json');
    }
  ],

Which renders the otherstuff.json.php template, but as if it were html.
I canā€™t see anything different in comparing the Page object here with a route composed directly of a content pageā€¦

(This isnā€™t critical to me right now btw, more of a theoretical scenario, I guess it would be important if I wanted to set a lot of routes as API endpoints?)

What is in your otherstuff.json.php template, then??

Not much:

<?php
// $kirby->response()->code(200)->type('application/json');
// ^ required if called via custom route, but not normally.

$data = [];
foreach($kirby->collection("otherstuff") as $child) {
  $childArray = $child->toArray();
}
echo json_encode($data);

I have a similar json template that is rendered from a real page, which works fine, so am fairly sure it is related to creating this via a route. But it may not be possible right now, sounds like it could be related to https://github.com/getkirby/kirby/issues/1364