Returning JSON with Routes

I want to use AJAX to populate a dynamic modal. To do this it seems using Routes is recommended according to this Kirby REST API via HTTP thread.

Currently I am receiving the error ā€œClass ā€˜piecepageā€™ not foundā€. What does this error mean?

//plugins/api.php
<?php

$prefix = "api/v1";

kirby()->routes([
  [
    'method' => 'GET',
    'pattern' => "{$prefix}/work",
    'action' => function() {

      $pieces = page('work')->children()->visible();
      $data = [];

      foreach ($pieces as $piece) {
        $data[] = $piece->serialize();
      }

      return response::json($data);
    }
  ]
]);

?>

Controller

//controllers/work.php
<?php

return function ($site, $pages, $page) {
  if (get('format') == 'json') {
    $data = [
      'uid'   => $page->uid(),
      'title' => $page->title()->toString(),
      'text'  => (string) $page->kirbytext(),
    ];

    die(response::json($data, 200));
  }
}

?>

Model

//models/piece.php
<?php

class WorkPage extends Page {
  public function serialize() {
    return [
      'uid'     => $this->uid(),
      'url'     => $this->url(),
      'title'   => $this->title()->html()->toString(),
      'text'    => $this->text()->kirbytext()->toString()
    ];
  }
}

?>

The name of your model file and the class name do not fit. Should be /models/work.phpwith class WorkPage.

1 Like

Thanks @texnixe, Iā€™m now getting the warning ā€œResource interpreted as Document but transferred with MIME type application/jsonā€ in the console when I hit /api/v1/work. I looked on StackOverflow and havenā€™t been able to work out what the problem is.

I only get that in Chrome, not Safari or Firefox; maybe due to the request not coming from an XMLHttpRequestā€¦?

Iā€™m trying to get a JSON response for the page /work/smile so I figure the call to the API should be api/v1/work/smile but Iā€™m getting a 404 response. Do I need to make another Model and Controller?

window.Kirby = {
   baseUrl: '<?php echo $site->url() ?>',
   url: function (path) {
        return this.baseUrl + (path && path[0] === '/' ? path : '/' + path);
   },
};

$('.piece').on("click", function(e) {
     e.preventDefault();
     var piece = $(this).data('slug')

     $.getJSON(Kirby.baseUrl + '/api/v1/work/' + piece, function(r) {
         console.log(r);
     });
});

HTML

<a href="//localhost:3000/ss/work/smile" class="piece" data-slug="smile">
      <img src="//localhost:3000/ss/content/work/3-smile/smile.gif"/>
 </a>

Well, your route only covers api/v1/work nothing after that?

1 Like

Thanks for the help @texnixe. Sorry for all the questions, Iā€™m trying to grasp the concept of routing. I want to amend my code so that I can have multiple routes. One that returns the JSON of all the pieces when I hit work and another when I hit a single piece like work/smile I get the JSON for only that page. How do I implement multiple routes in a plugin context?

<?php

$prefix = "api/v1";

kirby()->routes([
  [
    'method' => 'GET',
    'pattern' => "{$prefix}/work/",
    'action' => function() {

      $pieces = page('work')->children()->visible();
      $data = [];

      foreach ($pieces as $piece) {
        $data[] = $piece->serialize();
      }

      return response::json($data);
    }
  ],
  [
    'method' => 'GET',
    'pattern' => "{$prefix}/work/(:any)",
    'action' => function($id) {

      site()->visit($id);

      return response::json($data);
    }
  ],
]);

?>

$datais not defined in your second route, and I guess the path to the page is not only the id, but probably works plus ID?

Iā€™ve amended the code. I get a 200 response but there is no data attached to the response.

<?php

$prefix = "api/v1";

kirby()->routes([
  [
    'method' => 'GET',
    'pattern' => "{$prefix}/work/",
    'action' => function() {

      $pieces = page('work')->children()->visible();
      $data = [];

      foreach ($pieces as $piece) {
        $data[] = $piece->serialize();
      }

      return response::json($data);
    }
  ],
  [
    'method' => 'GET',
    'pattern' => "{$prefix}/work/(:any)",
    'action' => function($id) {

      $piece = site()->visit('work/' + $id);
      $data[] = $piece->serialize();

      return response::json($data);
    }
  ],
]);

?>

A + doesnā€™t work in PHP, thatā€™s Javascript syntax. Use a dot instead.

2 Likes