Customize endpoints

Custom endpoints

Once you have enabled a frontend to consume API you have a set of default available endpoints visible pointing the browser to your API base url.

Sometimes you would want to define other endpoints to serve your custom data to clients. You can do it simply override the $endpoints attribute of ApiBaseController.

Write in your ApiController

protected $endPoints = array('friends');

and define the related custom method that will handle the data to show

protected function friends() {
    $friendsList = array('Tom', 'Jerry');
    $this->setData($friendsList);
}

The setData() method takes care of put $friendsList array inside response data key. Point the browser to your API base url you should see ‘friends’ in the endpoints list and if you request GET /api/base/url/friends you should see

{
    "api": "friends",
    "data": [
        "Tom",
        "Jerry"
    ],
    "method": "get",
    "params": [],
    "url": "https://example.com/api/v1/friends"
}

In this way all request types (GET, POST, PUT, DELETE) have to be handled by friends() method. Another possibility is to create one method for every request type allowed from the endpoint. It can be done creating methods named “request type + endpoint camelized”.

protected function getFriends() {
}

protected function postFriends() {
}

protected function putFriends() {
}

protected function deleteFriends() {
}

Blacklist endpoints

In some situations you will not want to expose some or all default endpoints, so in order to disable them it is possible to define a blacklist. After that calling those endpoints the response will be a 405 Method Not Allowed HTTP error status code.

For example to blacklist “auth” and “objects” endpoints, in your ApiController override $blacklistEndPoints writing

protected $blacklistEndPoints = array('auth', 'objects');

Now, pointing to API base url you shouldn’t see “auth” and “objects” endpoints anymore.

Pointing to them directly and you will receive a 405 HTTP error.

Enable special object types endpoints

If you need you can also enable some special endpoint disabled by default. Those endpoints refer to BEdita object types mapping them to their pluralize form. So if you want to enable /documents end /galleries endpoints you have to edit ApiController

protected $whitelistObjectTypes = array('document', 'gallery');

These special endpoints automatically filter response objects through the object type related.

Again go to API base url to see ‘documents’ and ‘galleries’ added to endpoints list.

Note

Note that those special endpoints work only for GET requests.

Setup query string parameters

You can easily customize which query string parameters an endpoint can accept. By deafult every endpoint accepts the access_token query string (also if it is suggested to pass it in HTTP header Authorization). That is also valid for custom endpoints you create.

Moreover default endpoints support additional query string params according to ApiBaseController::$defaultAllowedUrlParams.

Every time a request is fullfilled with query strings parameters they are validated against those allowed. If validation fails the response return a 400 Bad Request status code.

To validate your own query string parameters there are two ways. Directly in ApiController or via configuration.

Configure allowed query string parameter in ApiController

To validate your own query string parameters you can define the $allowedUrlParams in ApiController as

protected $allowedUrlParams = array(
    'endpoint_name' => array('param_one', 'param_two')
);

Then you can send request as

GET /endpoint_name?param_one=value HTTP/1.1

without receive a 400 Bad Request error.

To group some parameters that you want to make availbale to more endpoints, the _ prefix can be used in the array keys. It will be considered as a special word used as group name instead of endpoint name.

protected $allowedUrlParams = array(
    // define a group of params
    '_paramGroup' => array('param_one', 'param_two'),
    // use group in endpoints
    'endpoint_one' => array('_paramGroup'),
    'endpoint_two' => array('_paramGroup', 'param_three')
);

Configure allowed query string parameter in configuration file

Using the same convention seen above you can customize the allowed query string editing app/config/frontend.ini.php or app/config/frontend.cfg.php

$config['api'] = array(
    'baseUrl' => '/api',
    // other conf params
    // ...
    'validation' => array(
        'allowedUrlParams' => array(
            // define a group of params
            '_paramGroup' => array('param_one', 'param_two'),
            // use group in endpoints
            'endpoint_one' => array('_paramGroup'),
            'endpoint_two' => array('_paramGroup', 'param_three')
        )
    )
);

Add allowed query string parameters on the fly

If you need to change the allowed parameters on the fly ApiValidator provides a method to register them.

// In ApiController
$allowedParams = array('objects' => 'custom_param');
// add "custom_param" to "objects" endpoint allowed params
$this->ApiValidator->registerAllowedUrlParams($allowedParams);

// or if you want override all rules with new one
$this->ApiValidator->registerAllowedUrlParams($allowedParams, false);

Customize /objects endpoint

Here we’ll see how to customize the objects endpoint.

Configure your own URL path filter types

objects endpoint can be customized with URL path filters building endpoint structured as /objects/:id/url_path_filter. URL path filters on by default are visible in ApiBaseController::$allowedObjectsUrlPath property

protected $allowedObjectsUrlPath = array(
        'get' => array(
            'relations',
            'children',
            'contents',
            'sections',
            'descendants',
            'siblings',
            //'ancestors',
            //'parents'
        ),
        'post' => array(
            'relations',
            'children'
        ),
        'put' => array(
            'relations',
            'children'
        ),
        'delete' => array(
            'relations',
            'children'
        )
    );

URL path filters can be inhibited or new ones can be added overriding that property in ApiController.

In practice URL path filters are divided by request type (GET, POST, ...) so it is possible doing request like GET /objects/1/children, POST /objects/1/relations but not POST /objects/1/siblings because of that filter is active only for GET requests.

Every URL path filter must have a corresponding controller method named “request type + Objects + URL path filter camelized” that will handle the request. First url part :id and every other url parts after URL path filter will be passed to that method as arguments.

For example, supposing to want to remove all ‘delete’ and ‘post’ URL path filters and add a new ‘foo_bar’ filter for GET request, in ApiController we can override

protected $allowedObjectsUrlPath = array(
        'get' => array(
            'relations',
            'children',
            'contents',
            'sections',
            'descendants',
            'siblings',
            'foo_bar'
        ),
    );

and add the method

protected function getObjectsFooBar($objectId) {
    // handle request here
}

In this way the new URL path filter is active and reachable from GET /objects/:id/foo_bar. Every other request type (POST, PUT, DELETE) to that will receive 405 Method Not Allowed.

If our ‘foo_bar’ URL path filter have to support GET /objects/:id/foo_bar/:foo_val requests then ApiController::getObjectsFooBar() will receive :foo_val as second argument. A best practice should be to add to method a validation on the number of arguments supported to avoid to respond to request as GET /objects/:id/foo_bar/:foo_val/bla/bla/bla.

protected function getObjectsFooBar($objectId, $fooVal = null) {
    if (func_num_args() > 2) {
        throw new BeditaBadRequestException();
    }
    // handle request here
}

Configure query string paramters to filter objects

Previoulsy we have seen how to add custom allowed query string params to endpoints.

The default allowed params are visible in GET /objects. In particular a special query string parameter is used to filter objects, its name is filter[] and it’s an array of conditions to apply to get collections of objects.

For example

GET /objects?filter[object_type]=document,gallery,event HTTP/1.1

will return a collection of publication’s descendants of type document or gallery or event. Filters are chained so you can do

GET /objects?filter[object_type]=document,gallery&filter[query]=test HTTP/1.1

to obtain a collection of publication’s descendants of type document or gallery containing the word “test” in some of their indexed fields.

In general you can define other useful filters with this convention

filter[objects_table_field_name]

where “objects_table_field_name” is a field of the objects table.

Or

filter[Model.field_name]

if you want to filter on a field in another table that extends objects table. For example if you want to filter by name field in cards table we would configure the allowed param filter[Card.name]

// frontend.ini.php
$config['api'] = array(
    'baseUrl' => '/api',
    // other conf params
    // ...
    'validation' => array(
        'allowedUrlParams' => array(
            'objects' => array('filter[Card.name]')
        )
    )
);

then we can search all publication’s descendants of type card with name equal to “Tom” or “Jerry”.

GET /objects?filter[object_type]=card&filter[Card.name]=Tom,Jerry HTTP/1.1