Upload
ontico
View
860
Download
5
Embed Size (px)
DESCRIPTION
HighLoad++ 2013
Citation preview
Wamba Open JSON APIРазработка и сопровождение API
в большом проекте
Сегодня в программе:
● Авто-документация. Генерация HTTP-роутинга.
● Архитектура основных компонентов API.
● Гибкое построение форм на клиенте: FormBuilder.
● Тестирование.
● Версионность.
Часть 1.
Документация.
Документация. Поиск решения
Документация может вестись отдельно, но тогда она быстро устаревает.
Для открытого API важнее актуальность документации.
Решение: документация должна быть в коде (phpdoc).
Документация в коде. Поиск решения.
NelmioApiDocBundle
<?php
/**
* @ApiDoc(
* description="CreateanewObject",
* input="YourType",
* output="YourClass"
*)
*/
public function postAction() {
}
• Используется нестандратныйphpdoc (99% не поддерживается IDE)
• Названия классов вшиты в строки (автоматический рефакториг затруднен)
Документация в коде. Поиск решения.
• Название классов API задается динамически (- рефакторинг)
Restler-API-Explorer
<?php
require_once '../../../vendor/restler.php';
use Luracast\Restler\Restler;
$r = new Restler();
$r->addAPIClass('Say');
$r->handle();
Документация в коде. Решение: ООП!/**
* Возращаем список пользователей
* @http_method get
* @uri /users/:userId/
* @param FiltersBroker\Authorized $fb
* @param Request\UserDetails $req
* @param Response\UserDetails $rsp
* @return Response\UserDetails
*/
public function getUserDetails(
FiltersBroker\Authorized $fb,
Request\UserDetails $req,
Response\UserDetails $rsp) { ...
● Генерируется автоматически IDE (PHPStorm)
● Имена классов (при сборке документации) берутся из типов атрибутов.
Генерация документации. Apigen
cd $PROJECT_HOME; make doc
apigen ...
PhpDoc + Apigen + Apigee = WebConsole
PhpDoc + Apigen + Apigee = WebConsole
Генерация HTTP-роутинга. Apigen.
class Service\User {
/**
* ...
* @http_method get
* @uri /users/:anketaId/
* ...
*/
public function getUserDetails(
FiltersBroker\Authorized $fb,
Request\UserDetails $req,
Response\UserDetails $rsp
) { ...
...
$this->map['GET']['/users/:anketaId/']
=function(){
return (new Service\User())
->getUserDetails(
new FiltersBroker\Authorized(),
new Request\UserDetails(),
new Response\UserDetails()
};
...
Часть 2.
Архитектура основных компонентов.
Архитектура. Обзор
• HTTP-роутер
Архитектура. Обзор
• HTTP-роутер• Брокер фильтров
public function getUserDetails( FiltersBroker\Authorized $fb, Request\UserDetails $req, Response\UserDetails $rsp }
Архитектура. Обзор
• HTTP-роутер• Брокер фильтров• Сервис
Архитектура. Обзор
• HTTP-роутер• Брокер фильтров• Сервис• Запрос
Архитектура. Обзор
• HTTP-роутер• Брокер фильтров• Сервис• Запрос• Ответ
Архитектура. Брокер Фильтров (FiltersBroker)
Проверяет доступ к сервису. class FiltersBroker\Authorized {
public function __construct() {
if (!\Profile::isAuthrorized()) {
throw new \AccessDeniedException();
}
...
}
}
● Настоящее предсобытие без “магических” конфигов.
● Передается в сервис как аттрибут (не потеряется).
Архитектура. Сервис (Service)
Бизнес-слойclass Service\User {
public function getUserDetails(
FiltersBroker\Authorized $fb,
Request\UserDetails $req,
Response\UserDetails $rsp
) {
// бизнес-логика. Использует только объекты API
// Весь код работы со сторонними библиотеками спрятан в DAO слой
}
}
Защищен брокером
Работает с конкретной структурой входных данных
Отдает ответ в соотвествии с конкретной структурой
Архитектура. Запрос (Request)
Описание полей входных данных /**
* Идентификатор пользователя
* @api
* @var int
* @example 12234
*/
protected $userId;
Архитектура. Запрос (Request)
Контроль типа через методы-аксессоры /**
* @return int
*/
public function getUserId() { return (int)$userId; }
/**
* Применяется при unit-тестировании
* @return void
*/
public function setUserId($userId) {
$this->userId = (int)$userId;
}
Архитектура. Запрос (Request)
Методы-помощники.
/**
* Метод-помощник.
* Возращает объект анкеты по установленному значению userId
* @return \User;
*/
public function getUser() {
}
Архитектура. Ответ (Response)
Описание полей ответа /**
* Идентификатор пользователя
* @api
* @var \User
* @example #object#
*/
protected $user;
Архитектура. Ответ (Response)
Контроль выходных данных через методы-аксессоры
public function getUser() {
if (!($this->user instanceof \User::getClass())) {
throw new \InvalidTypeException();
}
return $this->user;
}
Архитектура. Ответ (Response)
Сам себя превращает в JSON
class Response\UserDetails implements \JsonSerializable
{
public function jsonSerialize() {
return [
'user' => $this->getUser(),
];
}
}
Часть 3.
Гибкое построение форм на клиенте: FormBuilder.
Формы: FormBuilder. Цели
• Минимизировать ошибки на клиенте
• Иметь возможность модифицировать формы без релиза
• Сократить время разработки экрана-формы
Формы: FormBuilder. Пример.
{
"formBuilder": {
"blocks": [{
"name": "Авторизация",
"fields": [{
"name": "Электронная почта
или логин",
"inputType": "Text",
},
{
"name": "Пароль",
"inputType": "Password",
...
Часть 4.
Тестирование.
Функциональное тестирование. Behat
Scenario: Возвращает форму авторизации.
When I am on "/login/builder/?lang_id=ru"
Then I should see FormBuilder:
| block | field | type | enable |
| login | login | Text | true |
| | password | Password | true |
Функциональное тестирование. Behat
• Behat = Cucumber на PHP• Весь сложный код тестирования прячется за простым выражением
• Расширяем до +∞ /**
* @Then /^I should see FormBuilder:$/
*/
public function iShouldSeeFormBuilder(\Table $table) {
...
}
Функциональное тестирование. Behat
● Тестирование на естественном языке
● Проверка системы в продакшн с данными
● Отправная точка для unit-тестирования
Unit-тестирование. PHPUnit
• Проверка мелких узлов системы без данных
• Удаление зависимостей в коде
• Помогает делать код более простым
Рецепт: Отключите автозагрузку сторонних библиотек при unit-тестировании.
Часть 5.
Версионность.
Версионность. Внешняя
v5.1.0..1..2..
Мажорная версия API
Идентификатор платформы (iOS, Android)
Версия релиза клиента
Доступ к API: http://<домен-партнера>/mobile/api/v5.1.0/...
Версионность. Внутренняя
• Нет подверсий API
• Подверсии у стуктур данных
• Переход на подверсию API связан с изучением changelog, неодобряется бизнесом
• Переход на подверсию структуры быстр и касается только какого-то кокретного вызова API
Подверсии структур. Пример.
{
"name": "Прекрасный принц",
"photo": "photo250x250.jpg"
}
{
"name": "Прекрасный принц",
"photo": {
"square250": "photo250x250.jpg",
"square600": "photo600x600.jpg",
"large": "photoLarge.jpg"
}
}
Анкета версия 1 Анкета версия 2
Резюме:
• Генерация документации и HTTP-роутинга из phpdoc - Apigen
• Генерация web-console разработчика - Apigee
• Гибкий подход к формам на клиенте - FormBuilder
• Тестирование - Behat, PHPUnit
• Версионность: внешняя и внутренняя у структур.
Руководитель группы разработки мобильных сервисов Wamba
Каторгин Виталий ([email protected])
Спасибо за внимание!