Custom route to json content representation


#1

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?


#2

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:


#3

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!


#4

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');
          }
        ]
    ]

#5

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?)


#6

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


#7

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);

#8

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