Веб-сервисы

Создайте HTTP API для вашего сайта.

Elgg предоставляет мощный фреймворк для создания веб-сервисов. Это позволяет разработчикам предоставлять функциональность другим веб-сайтам и десктопным приложениям, а также выполнять интеграции со сторонними веб-приложениями. Хотя мы называем API RESTful, на самом деле это гибрид REST/RPC, подобный API, предоставляемым такими сайтами, как Flickr и X.

Чтобы создать API для вашего сайта на Elgg, вам нужно сделать 4 вещи:

  • включить плагин веб-сервисов

  • открыть методы

  • настроить аутентификацию API

  • настроить аутентификацию пользователей

Кроме того, вы можете захотеть контролировать, какие типы аутентификации доступны на вашем сайте. Это также будет рассмотрено.

Безопасность

Крайне важно, чтобы веб-сервисы потреблялись через безопасные протоколы. Не включайте веб-сервисы, если ваш сайт не обслуживается через HTTPS. Это особенно важно, если вы разрешаете аутентификацию только по ключу API.

Если вы используете сторонние инструменты, которые открывают методы API, обязательно проведите тщательный аудит безопасности. Возможно, вы захотите убедиться, что аутентификация API требуется для ВСЕХ методов, даже если они требуют аутентификации пользователя. Методы, не требующие аутентификации API, могут быть легко использованы для спама на вашем сайте.

Убедитесь, что срок действия ключей API ограничен, и предоставьте механизмы для обновления ключей вашими клиентами API.

Открытие методов

Методы API могут быть открыты одним из двух способов: - используя секцию web_services в файле elgg-plugin.php вашего плагина - во время события 'register', 'api_methods'

В качестве примера предположим, что вы хотите открыть функцию, которая возвращает текст обратно вызывающему приложению. Функция может выглядеть так

function my_echo($string) {
    return $string;
}

Поскольку мы предоставляем эту функцию для того, чтобы разработчики могли тестировать свои клиенты API, мы не будем требовать ни аутентификации API, ни аутентификации пользователя. Этот вызов регистрирует функцию во фреймворке API веб-сервисов:

// as part of the elgg-plugin.php
'web_services' => [
    'test.echo' => [
        'GET' => [ // the HTTP call method (GET|POST)
            'callback' => 'my_echo', // required
            'description' => 'A testing method which echos back a string', // optional, the description of the API method
            'params' => [ // optional, input parameters for the API method
                'string' => ['type' => 'string'],
            ],
            'require_api_auth' => false, // optional, requires API authentication (default: false)
            'require_user_auth' => false, // optional, requires User authentication (default: false)
            'associative' => false, // optional, provide the input params as an array to the callback function (default: false)
        ],
    ],
],

// as part of the 'register', 'api_methods' event
function my_plugin_event_handler(\Elgg\Event $event) {
    $results = $event->getValue();

    $results['test.echo']['GET'] = [
        'callback' => 'my_echo',
        'description' => 'A testing method which echos back a string',
        'params' => [
            'string' => ['type' => 'string'],
        ],
    ];

    return $results;
}

Примечание

Если в определении метода API не предоставлено description, система проверит наличие языкового ключа web_services:api_methods:<method>:<http call method>:description

Если вы добавите этот код в плагин, а затем перейдёте на http://yoursite.com/services/api/rest/json/?method=system.api.list, вы должны увидеть ваш метод test.echo в списке как вызов API. Далее, чтобы протестировать открытый метод из веб-браузера, вы можете перейти по URL: http://yoursite.com/services/api/rest/json/?method=test.echo&string=testing, и вы должны увидеть данные JSON, подобные этому:

{
    "status":0,
    "result":"testing"
}

Плагины могут фильтровать вывод отдельных методов API, зарегистрировав обработчик для события 'rest:output',$method.

Форматы ответов

JSON является форматом по умолчанию, однако XML и сериализованный PHP можно получить, включив плагин data_views и заменив xml или php вместо json в вышеуказанных URL.

Вы также можете добавить дополнительные форматы ответов, определив новые типы представлений.

Параметры

Параметры, ожидаемые каждым методом, должны быть перечислены как ассоциативный массив, где ключ представляет имя параметра, а значение содержит массив с полями type, default и required.

Значения, отправленные с запросом API для каждого параметра, должны соответствовать объявленному типу. API выбросит исключение, если проверка не пройдёт.

Распознаваемые типы параметров:

  • integer (или int)

  • boolean (или bool) 'false', 0 и '0' будут оцениваться как false, остальные будут оцениваться как true

  • string

  • float

  • array

Нераспознанные типы вызовут исключение API.

Вы можете использовать дополнительные поля для описания вашего параметра, например, description.

// as part of the elgg-plugin.php
'web_services' => [
    'test.greet' => [
        'GET' => [
            'callback' => 'my_greeting',
            'description' => 'A testing method which greets the user with a custom greeting',
            'params' => [
                'name' => [
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Name of the person to be greeted by the API',
                ],
                'greeting' => [
                    'type' => 'string',
                    'required' => false,
                    'default' => 'Hello',
                    'description' => 'Greeting to be used, e.g. "Good day" or "Hi"',
                ],
            ],
        ],
    ],
],

Примечание

Если отсутствующий параметр не имеет значения по умолчанию, аргумент будет null. До Elgg v2.1 ошибка приводила к сдвигу последующих аргументов влево в этом случае.

Получение параметров как ассоциативного массива

Если у вас большое количество параметров метода, вы можете заставить скрипт выполнения вызывать функцию обратного вызова с одним аргументом, который содержит ассоциативный массив пар параметр => ввод (вместо того, чтобы каждый параметр был отдельным аргументом). Для этого установите $assoc в true в elgg_ws_expose_function().

    function greet_me($values) {
            $name = elgg_extract('name', $values);
            $greeting = elgg_extract('greeting', $values, 'Hello');
            return "$greeting, $name";
    }

// as part of the elgg-plugin.php
'web_services' => [
    'test.greet' => [
        'GET' => [
            'callback' => 'greet_me',
            'description' => 'A testing method which echos a greeting',
            'params' => [
                'name' => [
                    'type' => 'string',
                ],
                'greeting' => [
                    'type' => 'string',
                    'required' => false,
                    'default' => 'Hello',
                ],
            ],
            'associative' => true,
        ],
    ],
],

Примечание

Если отсутствующий параметр не имеет значения по умолчанию, будет использовано null.

Аутентификация API

Возможно, вы захотите контролировать доступ к некоторым функциям, которые вы открываете. Возможно, вы открываете функции для интеграции Elgg с другой платформой с открытым исходным кодом на том же сервере. В этом случае вы хотите разрешить доступ к этим методам только этому другому приложению. Другая возможность — вы хотите ограничить доступ внешних разработчиков к вашему API. Или, возможно, вы хотите ограничить количество вызовов, которые разработчик может сделать к вашему API за один день.

Во всех этих случаях вы можете использовать функции аутентификации API Elgg для контроля доступа. Elgg предоставляет два встроенных метода для выполнения аутентификации API: на основе ключа и на основе подписи HMAC. Вы также можете добавить свои собственные методы аутентификации. Подход на основе ключа очень похож на то, что используют Google, Flickr или X. Разработчики могут запросить ключ (случайную строку) и передавать этот ключ со всеми вызовами, требующими аутентификации API. Ключи хранятся в базе данных, и если вызов API сделан без ключа или с неправильным ключом, вызов отклоняется и возвращается сообщение об ошибке.

Аутентификация на основе ключа

В качестве примера напишем функцию, которая возвращает количество пользователей, зарегистрировавшихся на вашем сайте с определённой временной метки.

function count_new_users(int $since) {
    return elgg_count_entities([
        'type' => 'user',
        'created_after' => $since,
    ]);
}

Теперь откроем её и сделаем количество минут обязательным параметром:

    // as part of the elgg-plugin.php
'web_services' => [
    'users.new' => [
        'GET' => [
            'callback' => 'count_new_users',
            'description' => 'Number of users who have used the site in the past x minutes',
            'params' => [
               'since' => [
                    'type' => 'int',
                    'required' => true,
                ],
            ],
            'require_api_auth' => true,
        ],
    ],
],

Эта функция теперь доступна, и если вы проверите system.api.list, вы увидите, что она требует аутентификации API. Если вы вызовете метод через веб-браузер, он вернёт сообщение об ошибке о неудачной аутентификации API. Для тестирования этого метода вам нужен ключ API. Начиная с Elgg 3.2 ключи API могут генерироваться плагином webservices. Он вернёт публичный и приватный ключ, и вы будете использовать публичный ключ для этого вида аутентификации API. Получите ключ, а затем выполните GET-запрос с помощью браузера к этому методу API, передав строку ключа в качестве параметра api_key. Это может выглядеть примерно так: http://yoursite.com/services/api/rest/xml/?method=users.active&api_key=1140321cb56c71710c38feefdf72bc462938f59f.

Аутентификация на основе подписи

Аутентификация HMAC похож на то, что используется с OAuth или сервисом Amazon S3. Это включает как публичный, так и приватный ключ. Если вы хотите быть полностью уверены, что вызовы API исходят от разработчика, от которого, как вы думаете, они исходят, и вы хотите убедиться, что данные не были изменены во время передачи, вы бы использовали этот метод аутентификации. Имейте в виду, что он гораздо более сложный и может отпугнуть разработчиков, когда есть другие сайты с аутентификацией на основе ключа.

Аутентификация пользователя

До сих пор вы позволяли разработчикам извлекать данные с вашего сайта на Elgg. Теперь перейдём к отправке данных в Elgg. В этом случае это будет делать пользователь. Возможно, вы создали десктопное приложение, которое позволяет вашим пользователям публиковать сообщения в ленту без захода на сайт. Вам нужно открыть метод для публикации в ленту, и вам нужно убедиться, что пользователь не может публиковать сообщения, используя чужой аккаунт. Elgg предоставляет подход на основе токенов для аутентификации пользователей. Он позволяет пользователю отправить своё имя пользователя и пароль в обмен на токен, используя метод auth.gettoken. Этот токен затем может использоваться в течение некоторого времени для аутентификации всех вызовов API до истечения его срока действия путём передачи его в качестве параметра auth_token. Если вы не хотите, чтобы ваши пользователи доверяли свои пароли сторонним приложениям, вы также можете расширить текущую возможность для использования подхода, подобного OAuth.

Напишем нашу функцию публикации в ленту:

function my_post_to_wire($text) {

    $text = elgg_substr($text, 0, 140);
    $post = new \ElggWire();

    $post->description = $text;
    $post->method = 'api';
    $post->save();

    // returns guid of wire post
    return $post->guid;
}

Открытие этой функции аналогично предыдущему, за исключением того, что мы требуем аутентификацию пользователя и будем использовать POST вместо GET HTTP-запросов.

    // as part of the elgg-plugin.php
'web_services' => [
    'thewire.post' => [
        'POST' => [
            'callback' => 'my_post_to_wire',
            'description' => 'Post to the wire. 140 characters or less',
            'params' => [
               'text' => [
                    'type' => 'string',
                ],
            ],
            'require_api_auth' => true,
            'require_user_auth' => true,
        ],
    ],
],

Обратите внимание, что вы не сможете протестировать это с помощью веб-браузера, как вы делали с другими методами. Вам нужно написать какой-то клиентский код для этого.

Развитие вашего API

Как только вы освоитесь с фреймворком API веб-сервисов Elgg, вы захотите отступить назад и спроектировать свой API. Какие данные вы пытаетесь открыть? Кто или что будет пользователями API? Как вы хотите, чтобы они получали доступ к ключам аутентификации? Как вы собираетесь документировать свой API? Обязательно посмотрите на API, созданные популярными сайтами Web 2.0, для вдохновения. Если вы ищете сторонних разработчиков для создания приложений с использованием вашего API, вы, вероятно, захотите предоставить один или несколько клиентов для конкретных языков.

Определение доступной аутентификации

API веб-сервисов Elgg использует архитектуру типа pluggable authentication module (PAM) для управления тем, как аутентифицируются пользователи и разработчики. Это предоставляет вам гибкость для добавления и удаления модулей аутентификации. Хотите ли вы не использовать PAM аутентификации пользователя по умолчанию, а предпочесть использование OAuth? Вы можете это сделать.

Первый шаг — регистрация функции обратного вызова для события 'rest', 'init':

elgg_register_event_handler('rest', 'init', 'rest_plugin_setup_pams');

Затем в функции обратного вызова вы регистрируете PAM, которые хотите использовать:

function rest_plugin_setup_pams() {
    // user token can also be used for user authentication
    elgg_register_pam_handler(\Elgg\WebServices\PAM\UserToken::class);

    // simple API key check
    elgg_register_pam_handler(\Elgg\WebServices\PAM\APIKey::class, 'sufficient', 'api');
}