Первые шаги в REST API

Всё что касается построения API
Ответить
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Первые шаги в REST API

Сообщение nepster »

Появилась потребность в создании rest api, ранее никогда с этим делам не работал, поэтому возникли вопросы.

И так, что мне нужно, это реализовать следующие экшины:
- создание маркета
- проверка уникального имени маркета
- редактирование маркета
- удаление маркета
- получение всех маркетов
- получение конкретного маркета по id
- получение кол-во маркетов по фильтру (например сколько всего маркетов в базе или сколько маркетов было создано за определенную дату)

Я почитал про рест апи и мне стали непонятны кое какие моменты. А именно:

Я пробовал создать все по примерам доков, создал контроллер и унаследовался от yii\rest\ActiveController

Код: Выделить всё

class MarketController extends ActiveController
{
    public $modelClass = 'rest\versions\v1\models\Market';
        
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['rateLimiter'] = [
            'class' => RateLimiter::className(),
            'enableRateLimitHeaders' => false,
        ];
        $behaviors['bootstrap'] = [
            'class' => ContentNegotiator::className(),
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
            ],
        ];
        return $behaviors;
    }
}
 
http://api.site/ru/v1/markets - честно отработал и вернул json ответ со всеми маркетами, как и написано в доках.

Как я понял yii\rest\ActiveController реализует по дефолту следующие методы (в моем случае для маркетов) :

Код: Выделить всё

    GET /users: разбитый на страницы список всех пользователей;
    HEAD /users: общая информация по списку пользователей;
    POST /users: создание нового пользователя;
    GET /users/123: подробная информация о пользователе 123;
    HEAD /users/123: общая информация о пользователе 123;
    PATCH /users/123 и PUT /users/123: обновление пользователя 123;
    DELETE /users/123: удаление пользователя 123;
    OPTIONS /users: список HTTP-методов, поддерживаемые точкой входа /users;
    OPTIONS /users/123: список HTTP-методов, поддерживаемые точкой входа /users/123.

Но что если мне нужны дополнительные методы или сделать какие либо действия для маркетов в определенных контроллерах ? Например различную валидацию при создании нового маркете или проверить права на удаления маркета или дописать фильтр выборки для получения всех маркетов (выбрать все маркеты со статусом 1), что делать в таком случае ?

Нужно описывать каждый экшин и унаследоваться просто от Controller, правильно ли я понял ?
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Первые шаги в REST API

Сообщение slavcodev »

REST архитектура, не подразумевает дополнительные методы, только те что можно сделать через HTTP методы: GET/POST/PUT/DELETE и тд. HTTP не ставит каких-нибудь ограничений на собственные методы, но поддержка их клиентами, сомнительна.

Что за валидация? Валидация данных делается непосредственно перед изменением модели, в действиях POST/PUT/PATCH

Права на удаления - есть метод OPTIONS который возвращает методы, которые клиент может выполнять над моделью.

Фильтры - через query-параметры методы GET (/markets/?status=1), в REST понятие "человекопонятные ссылки" не требуется, REST API использует не человек а программа (клиент, подразумевается, клиентская приложение, а не человек)
Жду Yii 3!
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Первые шаги в REST API

Сообщение nepster »

Вы меня совсем не поняли. Я имел ввиду про методы контроллера (экшины).

Тоесть если мне нужно проводить валидацию данных при PUT и POST запросах, как это можно сделать ?
Если унаследоваться от yii\rest\ActiveController это как демо пример просто?
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Первые шаги в REST API

Сообщение nepster »

В общем приведу пример.

Я организовал свой контроллер:

Код: Выделить всё

<?php

namespace rest\versions\v1\components;

use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
use yii\filters\RateLimiter;
use yii\filters\ContentNegotiator;
use yii\web\Response;


class Controller extends  \yii\rest\Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['rateLimiter'] = [
            'class' => RateLimiter::className(),
            'enableRateLimitHeaders' => false,
        ];
        $behaviors['bootstrap'] = [
            'class' => ContentNegotiator::className(),
            'formats' => [
                'application/json' => Response::FORMAT_JSON,
            ],
        ];
        /*$behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                HttpBasicAuth::className(),
                HttpBearerAuth::className(),
                QueryParamAuth::className(),
            ],
        ];*/
        return $behaviors;
    }
} 

Создал контроллер маркетов и унаследовался от своего контроллера:

Код: Выделить всё

<?php

namespace rest\versions\v1\controllers;

use Yii;

class MarketController extends \rest\versions\v1\components\Controller
{
    /**
     * @inheritdoc
     */
    protected function verbs()
    {
        return [
            /*'index' => ['GET', 'HEAD'],
            'view' => ['GET', 'HEAD'],
            'create' => ['POST'],
            'update' => ['PUT', 'PATCH'],
            'delete' => ['DELETE'],*/
            'test' => ['GET'],
        ];
    }
    
    /**
     * Test
     */
    public function actionTest() 
    {
        return ['status' => 'OK'];
    }

}
 
Правила URL вот такие:

Код: Выделить всё

            'rules' => [
                'v1/markets/test' => 'v1/market/test',
            ], 
На экране видим:

Код: Выделить всё

{"status":"OK"} 


Теперь, я хочу сделать метод, который бы проверял маркет на существование по алиасу, я делаю следующее:

Код: Выделить всё

    
    /**
     * Проверить маркет на существование
     */
    public function actionCheck() 
    {
        $market = null;
        if ( ($alias = Yii::$app->request->get('alias')) !== NULL ) {
            $market = Market::find()
                                ->where('alias = :alias', [':alias' => $alias])
                                ->one();
        }
                
        return ['status' => ($market != null) ? 1 : 0];
    } 
На первый взгляд все работает. Собственно вопрос, иду в верном направлении ?
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Первые шаги в REST API

Сообщение slavcodev »

Я думаю ты не правильно понял принцип REST.
В нем нет никаких действий, вроде check и прочего.
Возможно тебе нужен не REST?
Жду Yii 3!
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Первые шаги в REST API

Сообщение nepster »

мы либо друг друга не понимаем либо я сам вообще ничего не понимаю.

Возьмем банальный пример. ВК апи. Там есть различные методы и возможности, например создать альбом, удалить альбом, добавить фото в альбом и тп.

Мне нужно реализовать примерно тоже-самое (имею ввиду АПИ для проекта, а не альбомы и тп.). Я хочу сделать метод в своем апи, который бы проверял наличие магазина в базе по алиасу (например tv-market).

Выглядит это так:
https://api.site.ru/marckets/check?alias=tv-market

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

REST это подход к запросам, который обеспечивает определенные методы к определенным действия, тоесть расширяет GET и POST дополнительными методами.

Объясните пожалуйста где я не прав ?
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Первые шаги в REST API

Сообщение slavcodev »

Вот именно API VK имеет создать (POST/PUT), удалить (DELETE), редактировать (PUT/PATCH) и там нет действий типа check.
REST - Representational State Transfer, что простыми словами передача состояний объекта (ресурса). Считали с сервера, изменили на клиенте, послали новое состояние на сервер. И т.д. Ни каких проверок нет.
Жду Yii 3!
nepster
Сообщения: 838
Зарегистрирован: 2013.01.02, 03:35

Re: Первые шаги в REST API

Сообщение nepster »

ну к примеру если вы хотите узнать сколько записей в блоге, вы же создадите отдельный метод, который вернет кол-во ?
Или вы получите все записи и только потом посчитаете их кол-во?
Аватара пользователя
slavcodev
Сообщения: 3134
Зарегистрирован: 2009.04.02, 21:42
Откуда: Valencia
Контактная информация:

Re: Первые шаги в REST API

Сообщение slavcodev »

В данном конкретном примере, я сделаю HEAD /posts/, который не вернет посты, т.к. HEAD запрос, но вернет заголовки, в том числе о количестве записей.

Если ты делаешь именно REST приложение, то у тебя не должно быть никаких методов, посчитать, отметить как-то и т.д.
У тебя есть только ресурсы (сущности или коллекции сущностей). Клиент может только запрашивать эти ресурсы, у себя их менять и присылать на сервер измененные.

Твой вопрос, можно решить и по другому, ввести ресурс PostCount
GET /posts/count/ и получить json к примеру, {count: 123}

Другой пример, который возможно поможет тебе понять мои мысли, количество просмотра поста. НЕЛЬЗЯ увеличивать счетчик при запросе поста GET /posts/123/. Это не верно с точки зрения REST принципов. GET запросы, ни в коем случае не должны менять что-то на сервере. Решения могут быть разные. Например получить пост на клиент GET /posts/123/ <- {views: 123}
Изменить атрибут объекта PUT /posts/123/ -> {views: 124}

Или ввести новый ресурс PostView. Добавление нового просмотра
POST /posts/123/views/ -> {ip: 8.8.8.8}

Надеюсь помог.
Жду Yii 3!
chegewolf
Сообщения: 2
Зарегистрирован: 2015.01.04, 21:34

Re: Первые шаги в REST API

Сообщение chegewolf »

nepster писал(а):ну к примеру если вы хотите узнать сколько записей в блоге, вы же создадите отдельный метод, который вернет кол-во ?
Или вы получите все записи и только потом посчитаете их кол-во?
Возможно вы имеете ввиду вот это:

1. добавляем в контроллер нашу кастомный экшен:

Код: Выделить всё

public function actionTest()
{
    return 'so good'    ;
}
Далее в конфиге прописываем наши пути:

Код: Выделить всё

......
'urlManager' => [
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'showScriptName' => false,
            'rules' => [
                [    'class' => 'yii\rest\UrlRule', 'controller' => 'v1/test',
                    'pluralize' => false,
                    'extraPatterns' => [
                        'GET test' => 'test', // это значит что будем принимать get
                        'POST test' => 'test', // это значит, что будем  принимать post
                    ],
                ],
            ],        
        ]
....
после этого отправляем запрос -

http://mydomain.my/api/web/v1/test/test

и получаем результат.


имя контроллера в текущем случае - TestController
chegewolf
Сообщения: 2
Зарегистрирован: 2015.01.04, 21:34

Re: Первые шаги в REST API

Сообщение chegewolf »

А если надо в родные Action (index, update и т.д.), добавить фильтрацию или еще что, можно делать так:

добавляем в наш контроллер функцию:

Код: Выделить всё

 public function actions()
    {
        return array_merge(
            parent::actions(),
            [
                'index' => [
                    'class' => 'yii\rest\IndexAction',
                    'modelClass' => $this->modelClass,
                    'prepareDataProvider' => function ($action) {
                        $model = new $this->modelClass;
                        $query = $model::find();
                        $dataProvider = new ActiveDataProvider(['query' => $query]);

                        $model->setAttribute('name', @$_GET['name']);
                        $query->andFilterWhere(['like', 'name', $model->name]);

                        return $dataProvider;
                    }
                ]
            ] 
        );
    }
}
Ответить