С момента своего появления архитектура RESTful переопределила то, как мы думаем (и создаем) программные приложения, разбивая сложные экосистемы приложений на более мелкие, более целенаправленные приложения, взаимодействующие друг с другом посредством вызовов RESTful.
Архитектура клиент-сервер позволяет веб-клиентам и мобильным приложениям взаимодействовать с одной и той же инфраструктурой (например, с помощью API на стороне сервера), чтобы обеспечить бесперебойную работу пользователей.
В этом руководстве я покажу вам, как создать RESTful API с помощью Yii framework (версия 2) — высокопроизводительного PHP-фреймворка на основе компонентов.
Предпосылки
В этом руководстве вам поможет базовое понимание фреймворка Yii и PHP. Тем не менее, я буду предоставлять краткие пояснения и ссылки на соответствующие части официальной документации на протяжении всего руководства. Если вам неясна какая-либо концепция, вы можете просмотреть связанный материал, прежде чем продолжить.
Кроме того, в вашей системе должно быть установлено следующее:
- PHP версии 7 или выше с включенным расширением PDO .
- Композитор установлен глобально
- Локальный сервер базы данных. Хотя в этом руководстве будет использоваться MySQL, вы можете выбрать предпочитаемого поставщика базы данных.
- Postman или аналогичное приложение для проверки конечных точек. Вы также можете использовать cURL для проверки конечных точек.
Что мы построим
В этом руководстве мы создадим API для библиотечного приложения. Это приложение будет обрабатывать два основных ресурса: Members и Books . Приложение позволит выполнять базовые операции CRUD для обоих ресурсов. Кроме того, участники смогут брать книги. Если книга была взята напрокат, другой пользователь не сможет взять ту же книгу.
Начиная
Создание приложения
Для начала создайте новое приложение с именем library-api
и переключитесь в каталог проекта, используя следующие команды.
composer create-project --prefer-dist yiisoft/yii2-app-basic library-api
cd library-api
Убедитесь, что приложение было успешно создано с помощью следующей команды.
php yii serve
По умолчанию приложение будет обслуживаться по адресу http://localhost:8080/ . Перейдите по URL-адресу и убедитесь, что он показывает страницу приветствия, которую вы можете увидеть ниже.
Вернитесь к терминалу и нажмите Control + C
, чтобы выйти из сервера.
Настройка базы данных
Используя предпочитаемое вами приложение для управления базами данных, создайте новую базу данных с именем library-api
. Затем обновите параметры подключения к базе данных, чтобы связать ваше приложение с вновь созданной базой данных. Для этого откройте config/db.php
и обновите возвращенный массив, чтобы он соответствовал показанному ниже, аккуратно заменив заполнители именем пользователя и паролем для вашей базы данных.
return [
'class' => 'yii\\db\\Connection',
'dsn' => 'mysql:host=localhost;dbname=library_api',
'username' => '<USERNAME>'
'password' => '<PASSWORD>',
'charset' => 'utf8',
];
Создание миграций
Затем создайте миграции для таблиц базы данных. Чтобы поместить миграции в контекст, приложение будет иметь три объекта, а именно:
- Участник: этот объект будет представлять члена библиотеки. Для этой статьи таблица участников будет содержать имена участников вместе с датой начала членства.
- Книга: этот объект будет представлять книгу, доступную в библиотеке. Для этой статьи таблица book будет содержать название книги, автора, год выпуска и информацию о том, доступна ли книга во временное пользование или нет.
- Ссуда: эта сущность будет управлять данными, связанными с процессом «заимствования» книги. Для этой статьи он будет содержать одолженную книгу, члена, который ее одолжил, дату, когда она была одолжена, и ожидаемую дату возврата.
Чтобы создать миграцию, используйте команду yii, указав migrate/create
имя создаваемой миграции. При запросе подтверждения введите yes
для создания миграции. В этой статье используйте приведенные ниже команды для создания необходимых миграций.
php yii migrate/create create_member_table
php yii migrate/create create_book_table
php yii migrate/create create_loan_table
По умолчанию файлы миграции находятся в каталоге миграции . Имена файлов миграции начинаются с буквы « m » и даты и времени в формате UTC , когда они были созданы. Например , m210408_150000_create_member_table.php .
Откройте migrations/m<ГГММДД_ЧЧММСС>_create_member_table.php и измените safeUp
функцию, чтобы она соответствовала следующему коду.
public function safeUp()
{
$this->createTable('member', [
'id' => $this->primaryKey(),
'name' => $this->string()->notNull(),
'started_on' => $this->dateTime()->defaultValue(date('Y-m-d H:i:s'))
]);
}
Отредактируйте safeUp
функцию migrations/m<ГГММДД_ЧЧММСС>_create_book_table.php , чтобы она соответствовала следующему коду.
public function safeUp()
{
$this->createTable('book', [
'id' => $this->primaryKey(),
'name' => $this->string(),
'author' => $this->string(),
'release_year' => $this->smallInteger(),
'is_available_for_loan' => $this->boolean()->defaultValue(true)
]);
}
Отредактируйте функции safeUp
и safeDown
для migrations/m<ГГММДД_ЧЧММСС>_create_loan_table.php , чтобы они соответствовали следующему коду.
public function safeUp()
{
$this->createTable('loan', [
'id' => $this->primaryKey(),
'book_id' => $this->integer(),
'borrower_id' => $this->integer(),
'borrowed_on' => $this->dateTime()
->defaultValue(date('Y-m-d H:i:s')),
'to_be_returned_on' => $this->dateTime()
]);
// create index for column `book_id`
$this->createIndex(
'idx-loan-book_id',
'loan',
'book_id'
);
// add foreign key for table `post`
$this->addForeignKey(
'fk-loan-book_id',
'loan',
'book_id',
'book',
'id',
'CASCADE'
);
// create index for column `borrower_id`
$this->createIndex(
'idx-loan-borrower_id',
'loan',
'borrower_id'
);
// add foreign key for table `post`
$this->addForeignKey(
'fk-loan-borrower_id',
'loan',
'borrower_id',
'member',
'id',
'CASCADE'
);
}
public function safeDown()
{
$this->dropForeignKey('fk-loan-borrower_id','loan');
$this->dropIndex('idx-loan-borrower_id', 'loan');
$this->dropForeignKey('fk-loan-book_id', 'loan');
$this->dropIndex('idx-loan-book_id', 'loan');
$this->dropTable('loan');
}
Заполнение базы данных
Чтобы некоторые данные были доступны при создании таблиц, мы можем создать миграции для вставки поддельных данных в базу данных. Создайте две новые миграции с помощью следующей команды:
php yii migrate/create seed_member_table
php yii migrate/create seed_book_table
Откройте migrations/m<ГГММДД_ЧЧММСС>_seed_member_table.php и измените safeUp
функцию и добавьте insertFakeMembers
функцию после нее, как в приведенном ниже коде.
public function safeUp() {
$this->insertFakeMembers();
}
private function insertFakeMembers()
{
$faker = \Faker\Factory::create();
for ($i = 0; $i < 10; $i++) {
$this->insert(
'member',
[
'name' => $faker->name
]
);
}
}
Затем откройте migrations/m<ГГММДД_ЧЧММСС>_seed_book_table.php и измените safeUp
функцию и добавьте insertFakeBooks
функцию после нее, как в приведенном ниже коде.
public function safeUp() {
$this->insertFakeBooks();
}
private function insertFakeBooks()
{
$faker = \Faker\Factory::create();
for ($i = 0; $i < 50; $i++) {
$this->insert(
'book',
[
'name' => $faker->catchPhrase,
'author' => $faker->name,
'release_year' => (int)$faker->year,
]
);
}
}
После внесения изменений запустите миграцию для создания таблиц с помощью следующей команды:
php yii migrate
При появлении запроса введите «да» и нажмите «Ввод», чтобы запустить миграцию. Откройте library-api
базу данных в предпочитаемом вами приложении, чтобы увидеть новую структуру таблицы.
Таблица книг с образцами книг показана ниже.
Таблица членов с образцами элементов показана ниже.
Создание моделей
Вместо написания необработанных SQL-запросов для взаимодействия с базой данных мы создадим классы Active Record для наших моделей. Это даст нам объектно-ориентированные средства доступа и хранения данных в базе данных. Создайте классы Active Record для сущностей Member , Book и Loan , используя приведенные ниже команды. При появлении запроса введите yes
и нажмите Enter
, чтобы продолжить.
php yii gii/model --tableName=member --modelClass=Member
php yii gii/model --tableName=book --modelClass=Book
php yii gii/model --tableName=loan --modelClass=Loan
Классы моделей сохраняются в каталоге моделей . Интересно, что они помогают нам генерировать функции для обработки сложных взаимосвязей в структуре нашей базы данных. Например, в models/Member.php для нас была создана getLoans
функция, которая извлекает все кредиты, связанные с данным участником. То же самое и с файлами models/Book.php .
Создайте контроллеры
Имея базу данных и модели, мы можем создавать контроллеры для обработки вызовов RESTful. Контроллеры Yii основаны на yii\rest\ActiveController , который обеспечивает общие действия RESTful. Это позволяет нам создавать конечные точки для обработки действий CRUD без необходимости самостоятельно писать шаблонный код.
Для начала создайте контроллеры для сущностей Member и Book, используя приведенные ниже команды. Введите «yes» и нажмите «Enter» при появлении запроса.
php yii gii/controller --controllerClass=app\\controllers\\MemberController --baseClass=yii\\rest\\ActiveController
php yii gii/controller --controllerClass=app\\controllers\\BookController --baseClass=yii\\rest\\ActiveController
Аргумент controllerClass
указывает имя создаваемого контроллера. Ожидается, что вы предоставите полностью квалифицированный класс с пространством имен.
Примечание . Двойные символы возврата ( \\
), используемые при указании пространства имен, необходимы для исключения одиночного возврата в полном имени класса.
Классы контроллера хранятся в каталоге контроллера . Откройте controllers/BookController.php и отредактируйте содержимое, чтобы оно соответствовало следующему.
<?php
namespace app\controllers;
class BookController extends \yii\rest\ActiveController {
public $modelClass = 'app\models\Book';
}
Таким же образом откройте controllers/MemberController.php и отредактируйте содержимое, чтобы оно соответствовало следующему.
<?php
namespace app\\controllers;
class MemberController extends \yii\rest\ActiveController
{
public $modelClass = 'app\models\Member';
}
Затем измените urlManager
компонент в конфигурации вашего приложения, которую вы найдете в config/web.php .
В config/web.php
, массив, хранящийся в $config
, возвращается. Этот массив содержит components
элемент. В этом элементе замените закомментированную версию urlManager
элемента следующим:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'member'],
['class' => 'yii\rest\UrlRule', 'controller' => 'book'],
],
],
Это изменение добавляет правило URL-адреса для контроллеров Member и Book, чтобы можно было получить доступ к связанным данным и управлять ими с помощью красивых URL-адресов и значимых HTTP-команд.
Этот components
элемент также содержит request
элемент, который содержит конфигурацию для Application Component запроса . Чтобы API мог анализировать ввод JSON, добавьте к request
элементу следующее.
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
На данном этапе у нас есть приложение, которое может обрабатывать следующие запросы:
Метод | Маршрут | Описание |
GET | /{members, books} | Список всех участников или книг страница за страницей; |
POST | /{members, books} | Создать нового участника или книгу; |
GET | /{members, books}/123 | Вернуть реквизиты члена или книги 123; |
PATCH and PUT | /{members, books}/123 | Обновить участника или книгу 123; |
DELETE | /{members, books}/123 | Удалить участника или книгу 123; |
Обслуживайте приложение, запустив php yii serve
и протестировав только что созданные конечные точки.
Например, чтобы получить список книг из базы данных, отправьте запрос GET на адрес http://localhost:8080/books
. Для этого запустите Postman, если он еще не открыт.
Если вы впервые используете Postman, вам нужно ввести конечную точку API, где написано « Введите URL-адрес запроса », и выбрать метод (тип действия) слева от этого поля. Метод по умолчанию — GET, и он подходит для нашего варианта использования. Затем нажмите кнопку « Отправить », расположенную справа от поля URL-адреса запроса. Этот процесс изображен на изображении ниже:
В случае успеха вы увидите ответ JSON, содержащий списки книг из базы данных и код состояния 200 Ok .
Затем создайте нового участника, отправив запрос POST http://localhost:8080/members
и введя соответствующие данные, как показано на снимке экрана ниже.
Обратите внимание, что ваши данные могут отличаться от этих, но вот как должны выглядеть необработанные запросы JSON:
{
"name": "olususi oluyemi",
"started_on": "2020-03-24 12:30:10"
}
Если запрос выполнен успешно, вы получите ответ JSON с кодом состояния 201 Created .
Последний контроллер, который нам нужен, — это контроллер LoanController
для управления запросами, связанными с кредитом. Что касается ссуд, API должен разрешать только запросы на создание новой ссуды, т. е. заимствование книги или просмотр всех ссуд в системе. Создайте с LoanController
помощью следующей команды. Введите yes и нажмите Enter при появлении запроса.
php yii gii/controller --controllerClass=app\\controllers\\LoanController
Примечание. Поскольку нам не нужны все действия RESTful, доступные в классе ActiveController, мы не указывали базовый класс. Сгенерированный контроллер по умолчанию будет расширять класс yii/web/Controller .
Прежде чем мы создадим действия для обработки запросов, нам нужно добавить новые правила маршрутизации для новых конечных точек API. В config/web.php добавьте следующее в конец rules
массива элементов в файле urlManager
element.
'GET loans' => 'loan/index',
'POST loans' => 'loan/borrow'
По завершении urlManager
код должен выглядеть так:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'member'],
['class' => 'yii\rest\UrlRule', 'controller' => 'book'],
'GET loans' => 'loan/index',
'POST loans' => 'loan/borrow'
],
],
Используя сокращенную нотацию, предоставленную Yii, мы можем указать маршрут для данного URL. URL предоставляется в качестве ключа с маршрутом к соответствующему действию в качестве значения. Добавляя к URL-адресу префикс HTTP-глагола, приложение может соответствующим образом обрабатывать URL-адреса с одним и тем же шаблоном (для разных действий). Подробнее об этом можно прочитать здесь .
Чтобы API мог обрабатывать запросы POST, проверка CSRF будет отключена в файле LoanController
. Для этого в controllers/LoanController.php добавьте следующую переменную-член.
public $enableCsrfValidation = false;
Примечание. Отключение CSRF без дополнительных проверок может подвергнуть ваше приложение угрозам безопасности. Подробнее об этом читайте здесь .
Затем обновите метод LoanController
, actionIndex
чтобы он обрабатывал запрос на получение всех кредитов, заменив существующий код метода кодом, приведенным ниже.
public function actionIndex()
{
$loans = Loan::find()->all();
return $this->asJson($loans);
}
ПРИМЕЧАНИЕ . Не забудьте импортировать кредитную модель.
use app\models\Loan;
Перед созданием действия для обработки создания нового кредита добавьте вспомогательную функцию для возврата ответа об ошибке из API, добавив приведенный ниже код в конец файла LoanController
.
private function errorResponse($message) {
// set response code to 400
Yii::$app->response->statusCode = 400;
return $this->asJson(['error' => $message]);
}
ПРИМЕЧАНИЕ . Не забудьте импортировать Yii.
use Yii;
С внесенными изменениями, перед созданием нового кредита, приложение выполнит следующие проверки:
- Убедитесь, что
book_id
указанная книга соответствует существующей книге в базе данных. - Убедитесь, что выбранную книгу можно взять напрокат, т . е.
is_available_for_loan
она установлена наtrue
. - Убедитесь, что
member_id
предоставленный элемент соответствует существующему члену в базе данных.
Если какое-либо из вышеперечисленных условий не выполняется, errorResponse
следует вызвать функцию, вернув соответствующее ответное сообщение.
Перед созданием действия добавьте в модель Book функцию, позволяющую пометить книгу как заимствованную. Для этого в models/Book.php добавьте следующий код.
public function markAsBorrowed()
{
$this->is_available_for_loan = (int)false;
$this->save();
}
Затем создайте действие для обработки запроса на одолжение книги, добавив следующий код в файл controllers/LoanController.php
.
public function actionBorrow()
{
$request = Yii::$app->request;
$bookId = $request->post('book_id');
$book = Book::findOne($bookId);
if (is_null($book)) {
return $this->errorResponse('Could not find book with provided ID');
}
if (!$book->is_available_for_loan) {
return $this->errorResponse('This book is not available for loan');
}
$borrowerId = $request->post('member_id');
if (is_null(Member::findOne($borrowerId))) {
return $this->errorResponse('Could not find member with provided ID');
}
$loan = new Loan();
$returnDate = strtotime('+ 1 month');
$loan->attributes =
[
'book_id' => $bookId,
'borrower_id' => $borrowerId,
'borrowed_on' => date('Y-m-d H:i:s'),
'to_be_returned_on' => date('Y-m-d H:i:s', $returnDate)
];
$book->markAsBorrowed();
$loan->save();
return $this->asJson(
$loan
);
}
ПРИМЕЧАНИЕ . Не забудьте импортировать модели Book и Member.
use app\models\Member;
use app\models\Book;
Тестируйте новые маршруты
Вы можете протестировать новые маршруты, чтобы увидеть их в действии. Чтобы взять книгу, вы отправляете HTTP-запрос POST на эту конечную точку http://localhost:8080/loans . Введите конечную точку API в поле URL и выберите POST в раскрывающемся поле действия. Затем выберите Body в следующей строке и используйте следующий код в качестве примера необработанного запроса JSON:
{
"book_id": 9,
"member_id" : 10
}
Если запрос выполнен успешно, вы получите ответ JSON, аналогичный приведенному ниже, вместе с кодом состояния HTTP 200 OK:
{
"book_id": 9,
"member_id" : 10,
"borrowed_on": "2021-03-25 21:39:32",
"to_be_returned_on": "2021-04-25 21:39:32",
"id": 6
}
Вывод
В этой статье мы создали RESTful API для небольшого библиотечного приложения с фреймворком Yii2. В ходе этого процесса мы увидели некоторые преимущества разработки с использованием среды Yii2, такие как создание функций (моделей, контроллеров и т. д.) с минимальным кодом/шаблоном, его безопасные по умолчанию функции для защиты приложений от SQL-инъекций и CSRF. атаки, и это лишь некоторые из них.
Кроме того, лежащая в основе философии структура кода позволяет нам использовать лучшие практики и шаблоны ООП, в результате чего код становится легче поддерживать.