Custom Endpoint for Sorting Entries in Collection?

How would I set up an API endpoint to retrieve entries from a collection with a scheme of

api/public/projects/1 (returns first entry)
api/public/projects/2 (second entry)

and so on?

Right now I’ve just got a custom API that retrieves the published entries in a collection without having to specify entries,

You can create your own Rest controller, for example if you are doing that in a custom addon:

bootstrap.php

// Include actions.
if (COCKPIT_API_REQUEST) {
  $this->on('cockpit.rest.init', function ($routes) {
    $routes['public'] = 'MyAddon\\Controller\\RestApi';
  });
}

in your controller: MyAddon/Controller/RestApi.php

<?php

namespace MyAddon\Controller;

use \LimeExtra\Controller;

/**
 * RestApi class for dealing with user reviews.
 */
class RestApi extends Controller {
  public function projects($id) {
    // Additional logic, validations, etc..
    // ...
    // Fetch the entry (filtering by the id, but you can use other field)
    $entry = $this->app->module('collections')->findOne('projects', ['_id' => $id]);
    // Manipulate entry if you need and return as you neeed.
    return ['project' => $entry, 'id' => $id];
  }

}

So you can access /api/myaddon/public/projects/<id>

Ok, bear with me here as I’m using Cockpit as my way to learn REST APIs, and I feel like I’m super close.

So in the bootstrap file of the addon, it fires when cockpit is queried at <CMS_URL>/api, then starts a function that passes in $routes. I’m a bit hazy here, but I’m guessing that $routes is the URL passed in?

It then takes that route (in this case, “public”, so /api/public) and then I’m a bit confused as to what the = 'MyAddon\\Controller\RestApi'; is for. Is that for pulling the query from the restapi?

The RestApi itself seems to make sense. Essentially, it passes in whatever value is in the url and then queries the specified collection for that value (id, slug, etc.) then returns it?

Just trying to make better sense of how the call/response works for this. Thanks!

That’s the Class that will bind to the public path, the path is composed by:

/api/<addon-name>/<endpoint-name>/<method-name>/<method-argument>

so /api/myaddon/public/projects/12345 matches above path

resuming, it will check for addon name and endpoint name and load the class that bind to it and will invoke the method projects of that class, that method receives the id as an argument.

Ok, that definitely makes sense now. I also looked through your ImageStyles plugin to get a better grasp of it. I’ve set this up myself, but whenever I query that path with one of my post’s IDs, I’m just given a response of:

{
  "error": "Unauthorized"
}

Next question would be, is the public path tied to the one that exists already in Cockpit, or my custom one? Right now, my custom one is just a “projects.php” file in config/api/ that returns that collection with only the published entries filtered. Or, is this error just from a misstep with API permissions?

Thanks again!

Alright. I can’t figure out what the issue is, and I don’t know if it’s binding with any routes at all.

Here’s what I’ve tried:

addons/MyAddon/bootstrap.php

<?php

if (COCKPIT_API_REQUEST) {
    $this->on('cockpit.rest.init', function ($routes) {
        $routes['public'] = 'MyAddon\\Controller\\RestApi';
    });
}

addons/MyAddon/Controller/RestApi.php

<?php

namespace MyAddon\Controller;

use \LimeExtra\Controller;

/**
 * RestApi class for dealing with user reviews.
 */
class RestApi extends Controller
{
    public function projects()
    {

        $entry = $this->app->module('collections')->find('Projects');

//        return ['project' => $entry, 'id' => $id];
        return ['project' => $entry];
    }
}

I’ve tried this just to see if I can can even fetch the collection “Projects” from:
https://cms.alternatingfocus.com/api/myaddon/public/projects

But I just receive the Unauthorized error.

And if I try to pull a specific ID from the collection by changing
/addons/MyAddon/Controller/RestApi.php to:

class RestApi extends Controller {
    public function projects($id) {
        $entry = $this->app->module('collections')->findOne('Projects', ['_id' => $id]);
        return ['project' => $entry, 'id' => $id];
    }
}

using: https://cms.alternatingfocus.com/api/myaddon/public/projects/5c4f6041326533525100022d

I still get the Unauthorized error. I’ve tried changing the route to $routes['public'] and querying it from https://cms.alternatingfocus.com/api/myaddon/testing/projects/5c4f6041326533525100022d to no avail.

What am I missing?

You need to use a token api, use the one from the master key or better generate a new one that is specific for that path, e.g:

image

Alright, made a new temporary key for this route to work on.

When I query it with or without the token, I get these results:

I thought binding it to the public route no longer required an API key for authentication?

the url format should be:

https://cms.alternatingfocus.com/api/myaddon/testing/projects/5c4f6041326533525100022d?token=xxxxxxxxxxxxxx

better to change your token paths to /api/myaddon/* (from the screenshot you have /api/myaddon/public/* but you are acessing the url /api/myaddon/testing/projects

Ok, this is bizarre.

I changed my API token to /api/myaddon/*

I’m no longer receiving Not Authorized, now I’m receiving:

Is this an issue with the Lime Controller? I’ve tried changing the projects() method (leaving all the other code the same, save for the routes is pointing to testing) to just return("hello"), to see if it’s even reaching it’s endpoint, and I’m still getting Path Not Found.

You probably have something wrong, can you paste (only the main definition) the code of the addon:

  • when you are binding the controller
  • the controller

Sure thing.

addons/MyAddon/bootstrap.php

if (COCKPIT_API_REQUEST) {
    $this->on('cockpit.rest.init', function ($routes) {
        $routes['testing'] = 'MyAddon\\Controller\\RestApi';
    });
}

addon/MyAddon/Controller/RestApi.php

namespace MyAddon\Controller;

use \LimeExtra\Controller;

class RestApi extends Controller {
    public function projects($id) {
        $entry = $this->app->module('collections')->findOne('Projects', ['_id' => $id]);

        return ['project' => $entry, 'id' => $id];
    }

}

can you try to access:

http://cockpit-url/api/testing/projects/?token=xxxxx

ensure that you have the api keys configured to have access to /api/testing/*

There it is. Got it. It works great now. I guess the URL that I was accessing it from was the ticket. It looks like the /myaddon/ part of it wasn’t necessary? Either way, this is now working great! Thank you so much for helping out with this conundrum.

1 Like