Проверь нас в деле за один месяц

Разработка веб-приложения с Laravel + React: разбор технических деталей58 просмотров

Автор

Егор Терлецкий

Технический директор

Время на прочтение
6 минут
Дата публикации
12 февраля, 2025

Laravel и React — это две популярные технологии веб-разработки, используемые для создания современных веб-приложений. Laravel — это, в основном, серверная сторона, тогда как React — это клиентская JavaScript библиотека. Этот руководство служит введением в Laravel и React, объединяя их для создания современного веб-приложения.

В современном веб-приложении серверная сторона ограниченна бекендом через некоторые конечные точки входа API (Application Programming Interface). Клиент отправляет запросы этим конечным точкам, и сервер возвращает ответ. Однако сервер не заботится о том, как клиент выводит представление, что идеально соответствует принципу разделения ответствености. Эта архитектура позволяет разработчикам создавать надежные веб приложения, а также приложения  для разных устройств.

В этом руководстве мы будем использовать последнюю версию Laravel версии 5.5 для создания RESTful API. Фронтэнд будет состоять из компонентов, написанных на React. Мы будем создавать поисковое приложение для листинга продуктов. В первой части руководства основное внимание будет уделено концепциям Laravel и бекенду. Давайте начнем.

Side image

Введение

Laravel — это PHP-фреймворк, разработанный для современного веба. У него есть выразительный синтаксис, который поощряет парадигму соглашение над конфигурационной. У Laravel есть все возможности прямо из коробки, которые вам нужны для старта проекта. Но лично мне нравится Laravel, потому что он превращает разработку на PHP в совершенно другой опыт и рабочий процесс.

С другой стороны, React — популярная JavaScript библиотека, разработанная в Facebook для создания одностраничных приложений. React поможет вам разбить ваши представления на компоненты, в которых каждый компонент описывает часть пользовательского интерфейса приложения. Компонентный подход имеет дополнительное преимущество повторного использования компонентов и модульности.

Почему Laravel и React?

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

Итак, насколько хорошо Laravel и React подходят друг другу? на самом деле довольно хорошо. Хотя в документации Laravel заявлена поддержка для Vue.js, что является еще одним JavaScript фреймворком, для клиентской стороны мы будем использовать React , потому что он более популярен.

Предварительное условие

Прежде чем приступить к работе, я собираюсь предположить, что у вас есть базовое представление об архитектуре RESTful и о том, как работают конечные точки API. Кроме того, если у вас есть предыдущий опыт в React или Laravel, вы сможете извлечь максимальную пользу из этого руководства.

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

Установка и настройка Laravel проекта

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

Выполните следующую команду для загрузки и установки laravel.

1
composer global require "laravel/installer"

Если вы правильно настроили переменную $PATH и добавили ~/.composer/vendor/bin в свой путь, вы должны создать новый проект Laravel следующим образом:

1
laravel new PROJECT-NAME

Кроме того, вы можете использовать Composer для создания нового проекта без установщика laravel.

1
composer create-project --prefer-dist laravel/laravel blog

Если все будет хорошо, вы сможете запустить свое приложение на сервере разработки по адресу http://localhost:8000.

1
php artisan serve

Примечание: Artisan — это инструмент командной строки, без которого не обойтись при работе с Laravel. Artisan принимает большой список команд, которые позволяют генерировать код для вашего приложения. Запустите php artisan list, чтобы просмотреть все доступные команды.

Настройка среды

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

1
DB_CONNECTION=mysql
2
DB_HOST=127.0.0.1
3
DB_PORT=3306
4
DB_DATABASE=sampledb
5
DB_USERNAME=root
6
DB_PASSWORD=

Общие сведения о моделях, роутах и контроллерах

Laravel — это фреймворк, который следует архитектуре Model-View-Controller (MVC). Проще говоря, MVC помогает вам отделить запросы к базе данных (Модель) от логики, связанной с тем, как должны обрабатываться запросы (контроллер) и как должен быть отображен макет (вид). На изображении ниже демонстрируется работа типичного Laravel приложения.

Overview of Laravels architecture for building RESTful API endpoints

Архитектура Laravel. Контроллер возвращает ответ, и, следовательно, слой представления не требуется.

Поскольку мы создаем API с использованием Laravel, мы ограничим наше обсуждение моделью и контроллером. Мы рассмотрим наши варианты создания представления во второй части этого руководства.

Роутинг

Когда сервер получает HTTP-запрос, Laravel пытается сопоставить его с роутом, зарегистрированным внутри любого из файлов роутинга. Все файлы роутинга находятся внутри соответсвующего каталога. route/web.php содержит роуты для веб-интерфейса, тогда как route/api.php содержит роуты для API. Роуты, зарегистрированные в api.php, будут иметь префикс /api (как в localhost:3000/api). Если вам нужно изменить это поведение, вы должны перейти в класс RouteServiceProvider в /app /Providers /RouteServiceProvider.php и внести туда изменения.

Поскольку мы создаем приложение для списка продуктов, здесь указаны конечные точки API и HTTP-методы, связанные с этими конечными точками.

  • GET /products/: Получение всех продуктов.
  • GET /product/{id}: Получение продукта, соответствующего id.
  • POST /products: Создание нового продукта и вставка его в базу данных.
  • PUT /products/{id}: Обновление существующего продукта, соответствующего id.
  • DELETE /products/{id}: Удаление продукта с заданным id.

Давайте вернемся к терминологии. GET, POST, PUT и DELETE — это HTTP-глаголы (более известные как HTTP-методы), необходимые для создания RESTful-сервиса. /products — это URI, связанный с ресурсом продуктов. HTTP-методы  запрашивают сервер для выполнения желаемого действия на заданном ресурсе.

HTTP actions acting on the Product resource
GET, POST, PUT и DELETE являются наиболее часто используемымы действиями REST

Роутер позволяет объявлять роуты для ресурса вместе с HTTP-методами, которые нацелены на этот ресурс. Вот пример файла роутинга, который возвращает некоторые жестко кодированные данные.

routes/api.php

1
/** 
2
** Basic Routes for a RESTful service: 
3
** 
4
** Route::get($uri, $callback); 
5
** Route::post($uri, $callback); 
6
** Route::put($uri, $callback); 
7
** Route::delete($uri, $callback); 
8
** 
9
**/
10

11
Route::get('products', function () {
12
    return response(['Product 1', 'Product 2', 'Product 3'],200);
13
});
14

15
Route::get('products/{product}', function ($productId) {
16
    return response()->json(['productId' => "{$productId}"], 200);
17
});
18
 
19

20
Route::post('products', function() {
21
    return  response()->json([
22
            'message' => 'Create success'
23
        ], 201);
24
});
25

26
Route::put('products/{product}', function() {
27
  return  response()->json([
28
            'message' => 'Update success'
29
        ], 200);
30
});
31

32
Route::delete('products/{product}',function() {
33
	return  response()->json(null, 204);
34
});

Если вы хотите проверить, что роуты работают должным образом, вы должны использовать тулинг, например POSTMAN или curl.

Модель продукта

Ресурсу продуктов требуется модель, которая может взаимодействовать с базой данных. Модель — это слой, который находится поверх базы данных, скрывая все специфичные для базы данных детали. Laravel использует Eloquent ORM для моделирования базы данных.

Eloquent ORM, входящий в состав Laravel, обеспечивает красивую, простую реализацию ActiveRecord для работы с вашей базой данных. Каждая таблица базы данных имеет соответствующую «Модель», которая используется для взаимодействия с этой таблицей. Модели позволяют запрашивать данные из ваших таблиц, а также вставлять новые записи в таблицу.
— Laravel Docs

Что относительно определения схемы базы данных? Миграция Laravel’а позаботится об этом. У Artisan есть команда миграции, которая позволяет вам определять вашу схему и постепенно обновлять ее на более позднем этапе. Давайте создадим модель и миграции для сущьности Product.

1
$ php artisan make:model Product -m

Примечание: Есть множество команд Artisan, и их легко забыть. Таким образом, каждая команда artisan включает хелпер, который отображает дополнительную информацию, такую ​​как доступные параметры и аргументы. Чтобы перейти на страницу справки, имя команды должно сопровождаться c help. Выполните следующую команду help, чтобы увидеть, что означает параметр -m$ php artisan help make: model.

Вот файл миграции.

database /migrations/ timestamp_create_products_table.php

1
<?php
2

3
use Illuminate \Support \Facades \Schema;
4
use Illuminate \Database \Schema \Blueprint;
5
use Illuminate \Database \Migrations \Migration;
6

7
class CreateProductsTable extends Migration
8
{
9
  
10
    public function up()
11
    {
12
        Schema::create('products', function (Blueprint $table) {
13
            $table->increments('id');
14
            $table->timestamps();
15
        });
16
    }
17

18
  
19
    public function down()
20
    {
21
        Schema::dropIfExists('products');
22
    }
23
}

Метод up вызывается при переносе новых таблиц и столбцов в базу данных, тогда как метод down вызывается при откате миграции. Мы создали схему для таблицы с тремя столбцами: idcreated_at и updated_at. Метод $table->timestamps() отвечает за сохранение столбцов created_at и updated_at. Давайте добавим еще пару строк в определение схемы.

1
   /* Let's add columns for title, description, price, availability */
2
   
3
   public function up()
4
    {
5
        Schema::create('products', function (Blueprint $table) {
6
            $table->increments('id');
7
            $table->timestamps();
8
            $table->string('title');
9
            $table->text('description');
10
            $table->integer('price');
11
            $table->boolean('availability');
12
        });
13
    }

Мы обновили схему с четырьмя новыми столбцами. Конструктор схем Laravel поддерживает множество типов столбцов, таких как stringtextintegerboolean и т. д.

Чтобы выполнить ожидающие миграции, вы должны выполнить следующую команду:

1
php artisan migrate

По соглашению, Laravel предполагает, что модель Product связана с таблицей products. Однако, если вам нужно связать модель с пользовательским именем таблицы, вы можете использовать свойство $table для объявления имени таблицы. Затем модель будет связана с таблицей с именем custom_products.

1
protected $table = 'custom_products';

Но мы оставим все на своих местах и продолжим пользоваться соглашениями. Сгенерированная модель продукта находится внутри каталога app/. Хотя класс модели может казаться пустым, он оснащен различными методами построения запросов, которые можно использовать для запросов к базы данных. Например, вы можете использовать Product::all() для извлечения всех продуктов или Product::find(1) для получения определенного продукта с id 1.

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

app/Product.php

1
/* Add the fillable property into the Product Model */
2

3
protected $fillable = ['title', 'description', 'price', 'availability'];

Вышеуказанный код присваивает атрибуты title, description, price и availability и рассматривает их как назначаемые массово. Теперь мы можем использовать метод Product::create для вставки новых строк в таблицу продуктов.

Заполнение базы данных

Laravel позволяет вам заполнить базу данных разработки и продакшена фиктивными данными, которые затем можно использовать для тестирования конечных точек API. Вы можете создать класс seed, выполнив следующую команду Artisan.

1
$ php artisan make:seeder ProductsTableSeeder

Сгенерированные файлы сидов будут помещены в каталог database/seeds.

Чтобы создать фиктивные данные, вы можете использовать что-то вроде str_random(10), которое возвращает случайную строку. Но если вам нужны данные, которые достаточно близки к фактическим данным, вы должны использовать что-то вроде библиотеки faker. Faker — это сторонняя библиотека, которая поставляется с Laravel для генерации фейковых данных.

database /seeds /ProductsTableSeeder.php

1
use App \Product;
2

3
class ProductsTableSeeder extends Seeder
4
{
5
    public function run()
6
    {
7

8
        $faker = \Faker\Factory::create();
9

10
        // Create 50 product records 
11
        for ($i = 0; $i < 50; $i++) {
12
            Product::create([
13
                'title' => $faker->title,
14
                'description' => $faker->paragraph,
15
                'price' => $faker->randomNumber(2),
16
                'availability' => $faker->boolean(50)
17
            ]);
18
        }
19
    }
20
}

Выполните команду artisan db:seed для заполнения базы данных.

1
$ php artisan db:seed --class=ProductsTableSeeder

Вернемся к routes/api.php и добавим недостающие части.

routes/api.php

1
/** 
2
**Basic Routes for a RESTful service: 
3
**Route::get($uri, $callback); 
4
**Route::post($uri, $callback); 
5
**Route::put($uri, $callback); 
6
**Route::delete($uri, $callback); 
7
** 
8
*/
9
Route::get('products', function () {
10
    return response(Product::all(),200);
11
});
12

13
Route::get('products/{product}', function ($productId) {
14
    return response(Product::find($productId), 200);
15
});
16
 
17

18
Route::post('products', function(Request $request) {
19
   $resp = Product::create($request->all());
20
    return $resp;
21

22
});
23

24
Route::put('products/{product}', function(Request $request, $productId) {
25
    $product = Product::findOrFail($productId);
26
    $product->update($request->all());
27
    return $product;
28
});
29

30
Route::delete('products/{product}',function($productId) {
31
	Product::find($productId)->delete();
32

33
    return 204;
34

35
});

Контроллер

В файле роутинга в настоящее время размещается логика роутинга и обработки запросов. Мы можем переместить логику обработки запросов в класс контроллера, чтобы наш код был лучше организован и более читабельным. Давайте сначала сгенерируем класс контроллера.

1
$ php artisan make:controller ProductsController

Класс Controller состоит из различных методов (index, show, save, update и delete), которые соответствуют различным HTTP-действиям . Я переместил логику обработки запросов с роутинга в контроллер.

app /HTTP /Controllers /ProductsController.php

1
<?php
2

3
namespace App \Http \Controllers;
4

5
use Illuminate \Http \Request;
6
use App\Product;
7

8
class ProductsController extends Controller
9
{
10

11
    public function index()
12
	{
13
	    return Product::all();
14
	}
15

16
	public function show(Product $product)
17
	{
18
	    return $product;
19
	}
20

21
	public function store(Request $request)
22
	{
23
	    $product = Product::create($request->all());
24

25
	    return response()->json($product, 201);
26
	}
27

28
	public function update(Request $request, Product $product)
29
	{
30
	    $product->update($request->all());
31

32
	    return response()->json($product, 200);
33
	}
34

35
	public function delete(Product $product)
36
	{
37
	    $product->delete();
38

39
	    return response()->json(null, 204);
40
	}
41

42
}

routes/api.php

1
/** 
2
**Basic Routes for a RESTful service: 
3
**Route::get($uri, $callback); 
4
**Route::post($uri, $callback); 
5
**Route::put($uri, $callback); 
6
**Route::delete($uri, $callback); 
7
** 
8
*/
9

10

11
Route::get('products', 'ProductsController@index');
12

13
Route::get('products/{product}', 'ProductsController@show');
14

15
Route::post('products','ProductsController@store');
16

17
Route::put('products/{product}','ProductsController@update');
18

19
Route::delete('products/{product}', 'ProductsController@delete');
20

21

Если вы не заметили, я включил экземпляр Product в методы контроллера. Это пример неявной привязки Laravel. Laravel пытается сопоставить имя экземпляра модели Product $product с названием URI-сегмента {product}. Если совпадение найдено, экземпляр модели продукта вводится в действия контроллера. Если база данных не имеет продукта, она возвращает ошибку 404. Конечный результат такой же, как и раньше, но с меньшим количеством кода.

Откройте POSTMAN, и конечные точки продукта должны работать. Убедитесь, что заголовок Accept: application/json включен.

Валидация и обработка исключений

Если вы перейдете к несуществующему ресурсу, это то, что вы увидите.

The error page displayed for the NotFoundHTTPException

Исключение NotFoundHTTPException — это то, как Laravel отображает ошибку 404. Если вы хотите, чтобы сервер возвращал ответ JSON, вам придется изменить поведение обработки исключений по умолчанию. Laravel имеет класс Handler, предназначенный для обработки исключений, расположенный в app/Exceptions/Handler.php. Класс имеет два метода: report() и render(). Метод report полезен для отчетов и регистрации событий исключения, тогда как метод render используется для возврата ответа при возникновении исключения. Обновите метод render, чтобы вернуть ответ JSON:

app/Exceptions/Handler.php

1
public function render($request, Exception $exception)
2
  {
3
    
4
      if ($exception instanceof \Illuminate \Database \Eloquent \ModelNotFoundException) 
5
      {
6
       return response()->json([
7
            'message' => 'Resource not found'
8
        ], 404);
9
      }
10
      
11
      return parent::render($request, $exception);
12
  }

Laravel также позволяет нам валидировать входящие HTTP-запросы с помощью набора правил валидации и автоматически возвращать ответ в JSON, если валидация не прошла. Логика проверки будет помещена внутри контроллера. Объект Illuminate \Http \Request предоставляет метод validate, который мы можем использовать для определения правил валидации. Давайте добавим несколько валидаций в методе store.

app /HTTP /Controllers /ProductsController.php

1
public function store(Request $request)
2
    {
3
		$this->validate($request, [
4
        'title' => 'required|unique:products|max:255',
5
        'description' => 'required',
6
        'price' => 'integer',
7
        'availability' => 'boolean',
8
    ]);
9
	    $product = Product::create($request->all());
10

11
	    return response()->json($product, 201);
12
	}

Заключение

Теперь у нас есть рабочий API для приложения с листингом продуктов. Однако API не имеет базовых функций, таких как аутентификация и ограничение доступа к неавторизованным пользователям. У Laravel есть встроенная поддержка аутентификации, а создание API для нее делается относительно просто. Я рекомендую вам добавить API аутентификации в качестве упражнения.

Laravel и React — мощное сочетание для разработки современных веб-приложений. Этот стек позволяет создавать масштабируемые, удобные и производительные системы, используя лучшие практики серверной и клиентской разработки. При правильном подходе можно построить гибкую архитектуру, способную справляться с высокой нагрузкой и сложными бизнес-логиками. Важно следить за оптимизацией, безопасностью и удобством кода, что позволит разрабатывать эффективные и поддерживаемые приложения.

Поделиться статьей:

Другие статьи

5 минут

Статья подробно объясняет, почему компании переходят на Headless CMS, сравнивая их с традиционными системами, и раскрывает ключевые преимущества бесшовных архитектур для бизнеса

Это не просто тренд, а необходимость для современного бизнеса, стремящегося к гибкости, скорости и омниканальности

Егор Терлецкий

Технический директор

7 минут

Подробно раскрываем про интеграцию WordPress и Next.js, объясняя, как совместить удобство CMS с высокой производительностью современного фронтенда

Показываем, как можно объединить удобство управления контентом с высокой скоростью и гибкостью современного фронтенда

Егор Терлецкий

Технический директор

3 минуты

Создание сайта с учетом поисковой оптимизации (SEO) — это один из самых эффективных способов привлечения клиентов.

Создавая цифровые продукты, бренды 
и бизнесы, мы помогаем компаниям выявлять, исследовать новые возможности 
и реагировать на них

Егор Терлецкий

Технический директор

Больше статей