Лаб. работа "Создание веб-приложений с использованием Slim"
Цель работы
Изучение основ разработки веб-приложений с использованием фреймворка Slim. Освоение навыков создания простых веб-приложений, маршрутизации запросов и работы с шаблонами.
Введение
Slim — это микрофреймворк для PHP, который предназначен для быстрого и простого создания веб-приложений и API. Он минималистичен и предоставляет основные функции, необходимые для разработки, такие как маршрутизация запросов, обработка HTTP-сообщений и внедрение зависимостей.
Оборудование и ПО
- Компьютер с установленной операционной системой (Windows, macOS, Linux).
- Веб-сервер (Apache, Nginx) или встроенный сервер PHP.
- PHP версии 7.2 или выше.
- Composer — менеджер зависимостей для PHP.
- Браузер для тестирования приложений.
Теоретическая часть
- Основы Slim: Slim Framework предоставляет базовую структуру для веб-приложений и API. Его простота делает его идеальным для небольших приложений, где важны производительность и гибкость.
- Маршрутизация: В Slim маршруты определяются с помощью методов GET, POST, PUT и DELETE. Каждый маршрут связан с определенным URI и анонимной функцией, которая обрабатывает запрос.
- Middleware: Middleware позволяет изменять запросы и ответы на этапе их обработки, что удобно для реализации функций аутентификации, логирования и обработки ошибок.
- Внедрение зависимостей: Slim поддерживает внедрение зависимостей через контейнеры, такие как PHP-DI или Pimple.
Практическая часть
1. Установка Slim Framework
Установите Composer, если он еще не установлен.
Создайте новый проект и установите Slim:
1composer create-project slim/slim-skeleton [project-name]
2. Создание простого маршрута
В файле
public/index.phpдобавьте следующий код:1<?php 2use Psr\Http\Message\ResponseInterface as Response; 3use Psr\Http\Message\ServerRequestInterface as Request; 4use Slim\Factory\AppFactory; 5 6require __DIR__ . '/../vendor/autoload.php'; 7 8$app = AppFactory::create(); 9 10$app->get('/hello/{name}', function (Request $request, Response $response, $args) { 11 $name = $args['name']; 12 $response->getBody()->write("Hello, $name"); 13 return $response; 14}); 15 16$app->run();Запустите встроенный сервер PHP:
1php -S localhost:8080 -t publicОткройте браузер и перейдите по адресу
http://localhost:8080/hello/World.
3. Добавление Middleware
Добавьте middleware для логирования времени выполнения запросов:
1$app->add(function (Request $request, RequestHandler $handler): Response { 2 $start = microtime(true); 3 $response = $handler->handle($request); 4 $time = microtime(true) - $start; 5 $response->getBody()->write('<!-- Time: ' . $time . 'ms -->'); 6 return $response; 7});
4. Работа с шаблонами:
Установите Twig для работы с шаблонами:
1composer require slim/twig-viewНастройте Twig в
index.php:1use Slim\Views\Twig; 2use Slim\Views\TwigMiddleware; 3 4$app = AppFactory::create(); 5 6$twig = Twig::create('../templates', ['cache' => false]); 7$app->add(TwigMiddleware::create($app, $twig)); 8 9$app->get('/greet/{name}', function (Request $request, Response $response, $args) use ($twig) { 10 return $twig->render($response, 'greet.twig', ['name' => $args['name']]); 11}); 12 13$app->run();Создайте шаблон
templates/greet.twig:1<!DOCTYPE html> 2<html> 3<head> 4 <title>Greet</title> 5</head> 6<body> 7 <h1>Hello, {{ name }}!</h1> 8</body> 9</html>
5. Работа с базой данных
1. Установка и настройка базы данных
Для начала установим и настроим подключение к базе данных MySQL.
Установите MySQL на ваш компьютер, если он еще не установлен.
Создайте базу данных для вашего проекта. Например, назовем её
slim_app.1CREATE DATABASE slim_app;Создайте таблицу для пользователей в базе данных
slim_app.1CREATE TABLE users ( 2 id INT AUTO_INCREMENT PRIMARY KEY, 3 name VARCHAR(255) NOT NULL, 4 email VARCHAR(255) NOT NULL UNIQUE 5);Установите зависимости для работы с базой данных через Composer.
1composer require vlucas/phpdotenv
2. Настройка подключения к базе данных
Создайте файл .env в корне вашего проекта и добавьте туда настройки подключения к базе данных.
1DB_HOST=127.0.0.1
2DB_NAME=slim_app
3DB_USER=root
4DB_PASS=your_password
Обновите файл index.php, чтобы загрузить переменные окружения и настроить подключение к базе данных.
1<?php
2use Psr\Http\Message\ResponseInterface as Response;
3use Psr\Http\Message\ServerRequestInterface as Request;
4use Slim\Factory\AppFactory;
5use DI\Container;
6use Dotenv\Dotenv;
7
8require __DIR__ . '/../vendor/autoload.php';
9
10// Загрузка переменных окружения
11$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
12$dotenv->load();
13
14$container = new Container();
15AppFactory::setContainer($container);
16
17$container->set('db', function() {
18 $host = $_ENV['DB_HOST'];
19 $db = $_ENV['DB_NAME'];
20 $user = $_ENV['DB_USER'];
21 $pass = $_ENV['DB_PASS'];
22 $charset = 'utf8mb4';
23
24 $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
25 $options = [
26 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
27 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
28 PDO::ATTR_EMULATE_PREPARES => false,
29 ];
30
31 try {
32 return new PDO($dsn, $user, $pass, $options);
33 } catch (\PDOException $e) {
34 throw new \PDOException($e->getMessage(), (int)$e->getCode());
35 }
36});
37
38$app = AppFactory::create();
39
40$app->get('/users', function (Request $request, Response $response, $args) {
41 $db = $this->get('db');
42 $stmt = $db->query('SELECT * FROM users');
43 $users = $stmt->fetchAll();
44 $response->getBody()->write(json_encode($users));
45 return $response->withHeader('Content-Type', 'application/json');
46});
47
48$app->run();
3. Создание маршрута для добавления нового пользователя
Создайте форму для добавления нового пользователя и маршрут для обработки этой формы.
Добавьте шаблон формы
add_user.twigв папкуtemplates.1<!DOCTYPE html> 2<html> 3<head> 4 <title>Add User</title> 5</head> 6<body> 7 <h1>Add New User</h1> 8 <form action="/add_user" method="post"> 9 <label for="name">Name:</label> 10 <input type="text" id="name" name="name"> 11 <label for="email">Email:</label> 12 <input type="email" id="email" name="email"> 13 <button type="submit">Add User</button> 14 </form> 15</body> 16</html>Обновите файл
index.php, чтобы добавить маршрут для отображения формы и обработки данных из формы.1$app->get('/add_user', function (Request $request, Response $response, $args) use ($twig) { 2 return $twig->render($response, 'add_user.twig'); 3}); 4 5$app->post('/add_user', function (Request $request, Response $response, $args) { 6 $data = $request->getParsedBody(); 7 $name = $data['name']; 8 $email = $data['email']; 9 10 $db = $this->get('db'); 11 $stmt = $db->prepare('INSERT INTO users (name, email) VALUES (:name, :email)'); 12 $stmt->execute(['name' => $name, 'email' => $email]); 13 14 return $response->withHeader('Location', '/users')->withStatus(302); 15});
6. Реализация API для работы с данными
1. Подготовка базы данных
Для начала, убедитесь, что у вас уже создана таблица пользователей. Если нет, создайте её в базе данных slim_app.
1CREATE TABLE users (
2 id INT AUTO_INCREMENT PRIMARY KEY,
3 name VARCHAR(255) NOT NULL,
4 email VARCHAR(255) NOT NULL UNIQUE
5);
2. Обновление конфигурации Slim
Внесите следующие изменения в index.php, чтобы добавить маршруты для API:
1<?php
2use Psr\Http\Message\ResponseInterface as Response;
3use Psr\Http\Message\ServerRequestInterface as Request;
4use Slim\Factory\AppFactory;
5use DI\Container;
6use Dotenv\Dotenv;
7
8require __DIR__ . '/../vendor/autoload.php';
9
10// Загрузка переменных окружения
11$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
12$dotenv->load();
13
14$container = new Container();
15AppFactory::setContainer($container);
16
17$container->set('db', function() {
18 $host = $_ENV['DB_HOST'];
19 $db = $_ENV['DB_NAME'];
20 $user = $_ENV['DB_USER'];
21 $pass = $_ENV['DB_PASS'];
22 $charset = 'utf8mb4';
23
24 $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
25 $options = [
26 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
27 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
28 PDO::ATTR_EMULATE_PREPARES => false,
29 ];
30
31 try {
32 return new PDO($dsn, $user, $pass, $options);
33 } catch (\PDOException $e) {
34 throw new \PDOException($e->getMessage(), (int)$e->getCode());
35 }
36});
37
38$app = AppFactory::create();
39
40// Получение всех пользователей
41$app->get('/api/users', function (Request $request, Response $response, $args) {
42 $db = $this->get('db');
43 $stmt = $db->query('SELECT * FROM users');
44 $users = $stmt->fetchAll();
45 $response->getBody()->write(json_encode($users));
46 return $response->withHeader('Content-Type', 'application/json');
47});
48
49// Получение пользователя по ID
50$app->get('/api/users/{id}', function (Request $request, Response $response, $args) {
51 $id = $args['id'];
52 $db = $this->get('db');
53 $stmt = $db->prepare('SELECT * FROM users WHERE id = :id');
54 $stmt->execute(['id' => $id]);
55 $user = $stmt->fetch();
56 if ($user) {
57 $response->getBody()->write(json_encode($user));
58 return $response->withHeader('Content-Type', 'application/json');
59 } else {
60 $response->getBody()->write(json_encode(['message' => 'User not found']));
61 return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
62 }
63});
64
65// Создание нового пользователя
66$app->post('/api/users', function (Request $request, Response $response, $args) {
67 $data = $request->getParsedBody();
68 $name = $data['name'];
69 $email = $data['email'];
70
71 $db = $this->get('db');
72 $stmt = $db->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
73 $stmt->execute(['name' => $name, 'email' => $email]);
74 $user = [
75 'id' => $db->lastInsertId(),
76 'name' => $name,
77 'email' => $email
78 ];
79 $response->getBody()->write(json_encode($user));
80 return $response->withStatus(201)->withHeader('Content-Type', 'application/json');
81});
82
83// Обновление пользователя по ID
84$app->put('/api/users/{id}', function (Request $request, Response $response, $args) {
85 $id = $args['id'];
86 $data = $request->getParsedBody();
87 $name = $data['name'];
88 $email = $data['email'];
89
90 $db = $this->get('db');
91 $stmt = $db->prepare('UPDATE users SET name = :name, email = :email WHERE id = :id');
92 $stmt->execute(['name' => $name, 'email' => $email, 'id' => $id]);
93 $user = [
94 'id' => $id,
95 'name' => $name,
96 'email' => $email
97 ];
98 $response->getBody()->write(json_encode($user));
99 return $response->withHeader('Content-Type', 'application/json');
100});
101
102// Удаление пользователя по ID
103$app->delete('/api/users/{id}', function (Request $request, Response $response, $args) {
104 $id = $args['id'];
105 $db = $this->get('db');
106 $stmt = $db->prepare('DELETE FROM users WHERE id = :id');
107 $stmt->execute(['id' => $id]);
108 $response->getBody()->write(json_encode(['message' => 'User deleted']));
109 return $response->withHeader('Content-Type', 'application/json');
110});
111
112$app->run();
3. Тестирование API
Теперь, когда все маршруты настроены, вы можете протестировать их с помощью инструмента Postman или curl. Вот несколько примеров запросов:
Получение всех пользователей:
1curl -X GET http://localhost:8080/api/usersПолучение пользователя по ID:
1curl -X GET http://localhost:8080/api/users/1Создание нового пользователя:
1curl -X POST http://localhost:8080/api/users -d "name=John Doe&email=john.doe@example.com"Обновление пользователя по ID:
1curl -X PUT http://localhost:8080/api/users/1 -d "name=Jane Doe&email=jane.doe@example.com"Удаление пользователя по ID:
1curl -X DELETE http://localhost:8080/api/users/1
7. Реализация аутентификации
1. Подготовка базы данных
Для начала, добавим таблицу пользователей в базу данных slim_app, которая будет включать поля для имени, электронной почты и пароля.
1CREATE TABLE users (
2 id INT AUTO_INCREMENT PRIMARY KEY,
3 name VARCHAR(255) NOT NULL,
4 email VARCHAR(255) NOT NULL UNIQUE,
5 password VARCHAR(255) NOT NULL
6);
2. Настройка конфигурации Slim
Убедитесь, что ваш файл index.php настроен для подключения к базе данных и добавьте маршруты для регистрации и авторизации пользователей.
1<?php
2use Psr\Http\Message\ResponseInterface as Response;
3use Psr\Http\Message\ServerRequestInterface as Request;
4use Slim\Factory\AppFactory;
5use DI\Container;
6use Dotenv\Dotenv;
7use Slim\Middleware\SessionMiddleware;
8
9require __DIR__ . '/../vendor/autoload.php';
10
11// Загрузка переменных окружения
12$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
13$dotenv->load();
14
15$container = new Container();
16AppFactory::setContainer($container);
17
18$container->set('db', function() {
19 $host = $_ENV['DB_HOST'];
20 $db = $_ENV['DB_NAME'];
21 $user = $_ENV['DB_USER'];
22 $pass = $_ENV['DB_PASS'];
23 $charset = 'utf8mb4';
24
25 $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
26 $options = [
27 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
28 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
29 PDO::ATTR_EMULATE_PREPARES => false,
30 ];
31
32 try {
33 return new PDO($dsn, $user, $pass, $options);
34 } catch (\PDOException $e) {
35 throw new \PDOException($e->getMessage(), (int)$e->getCode());
36 }
37});
38
39$app = AppFactory::create();
40
41// Middleware для работы с сессиями
42$app->add(SessionMiddleware::class);
43
44// Регистрация пользователя
45$app->post('/register', function (Request $request, Response $response, $args) {
46 $data = $request->getParsedBody();
47 $name = $data['name'];
48 $email = $data['email'];
49 $password = password_hash($data['password'], PASSWORD_DEFAULT);
50
51 $db = $this->get('db');
52 $stmt = $db->prepare('INSERT INTO users (name, email, password) VALUES (:name, :email, :password)');
53 $stmt->execute(['name' => $name, 'email' => $email, 'password' => $password]);
54
55 $response->getBody()->write(json_encode(['message' => 'User registered successfully']));
56 return $response->withHeader('Content-Type', 'application/json');
57});
58
59// Авторизация пользователя
60$app->post('/login', function (Request $request, Response $response, $args) {
61 $data = $request->getParsedBody();
62 $email = $data['email'];
63 $password = $data['password'];
64
65 $db = $this->get('db');
66 $stmt = $db->prepare('SELECT * FROM users WHERE email = :email');
67 $stmt->execute(['email' => $email]);
68 $user = $stmt->fetch();
69
70 if ($user && password_verify($password, $user['password'])) {
71 $_SESSION['user_id'] = $user['id'];
72 $_SESSION['user_name'] = $user['name'];
73 $response->getBody()->write(json_encode(['message' => 'Login successful']));
74 } else {
75 $response->getBody()->write(json_encode(['message' => 'Invalid email or password']));
76 return $response->withStatus(401)->withHeader('Content-Type', 'application/json');
77 }
78 return $response->withHeader('Content-Type', 'application/json');
79});
80
81// Middleware для проверки аутентификации
82$authenticate = function (Request $request, RequestHandler $handler) {
83 if (!isset($_SESSION['user_id'])) {
84 $response = new \Slim\Psr7\Response();
85 $response->getBody()->write(json_encode(['message' => 'Unauthorized']));
86 return $response->withStatus(401)->withHeader('Content-Type', 'application/json');
87 }
88 return $handler->handle($request);
89};
90
91// Пример защищенного маршрута
92$app->get('/profile', function (Request $request, Response $response, $args) {
93 $response->getBody()->write(json_encode([
94 'user_id' => $_SESSION['user_id'],
95 'user_name' => $_SESSION['user_name']
96 ]));
97 return $response->withHeader('Content-Type', 'application/json');
98})->add($authenticate);
99
100$app->run();
3. Создание шаблонов для регистрации и авторизации
Добавьте следующие шаблоны в папку templates для страниц регистрации и авторизации.
register.twig:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Register</title>
5</head>
6<body>
7 <h1>Register</h1>
8 <form action="/register" method="post">
9 <label for="name">Name:</label>
10 <input type="text" id="name" name="name">
11 <label for="email">Email:</label>
12 <input type="email" id="email" name="email">
13 <label for="password">Password:</label>
14 <input type="password" id="password" name="password">
15 <button type="submit">Register</button>
16 </form>
17</body>
18</html>
login.twig:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Login</title>
5</head>
6<body>
7 <h1>Login</h1>
8 <form action="/login" method="post">
9 <label for="email">Email:</label>
10 <input type="email" id="email" name="email">
11 <label for="password">Password:</label>
12 <input type="password" id="password" name="password">
13 <button type="submit">Login</button>
14 </form>
15</body>
16</html>
4. Настройка маршрутов для отображения страниц регистрации и авторизации
Обновите index.php, чтобы добавить маршруты для отображения форм регистрации и авторизации.
1$app->get('/register', function (Request $request, Response $response, $args) use ($twig) {
2 return $twig->render($response, 'register.twig');
3});
4
5$app->get('/login', function (Request $request, Response $response, $args) use ($twig) {
6 return $twig->render($response, 'login.twig');
7});
5. Тестирование аутентификации
Теперь, когда все маршруты и шаблоны настроены, вы можете протестировать регистрацию и авторизацию пользователей.
- Откройте браузер и перейдите по адресу
http://localhost:8080/register, чтобы зарегистрировать нового пользователя. - Перейдите по адресу
http://localhost:8080/login, чтобы авторизоваться. - После успешной авторизации вы можете получить доступ к защищенному маршруту
http://localhost:8080/profile.
8. Интеграция с внешним API OpenWeatherMap
1. Регистрация и получение API ключа
- Перейдите на сайт OpenWeatherMap и зарегистрируйтесь, чтобы получить API ключ.
- Сохраните свой API ключ, он понадобится для запросов к API.
2. Настройка конфигурации Slim
Добавьте ваш API ключ в файл .env.
1WEATHER_API_KEY=your_api_key_here
3. Установка GuzzleHTTP
GuzzleHTTP — это PHP HTTP-клиент, который мы будем использовать для отправки запросов к API OpenWeatherMap.
1composer require guzzlehttp/guzzle
4. Создание шаблона для отображения данных о погоде
Добавьте следующий шаблон в папку templates для отображения данных о погоде.
weather.twig:
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Weather</title>
5</head>
6<body>
7 <h1>Weather in {{ city }}</h1>
8 {% if weather %}
9 <p>Temperature: {{ weather.main.temp }} °C</p>
10 <p>Weather: {{ weather.weather[0].description }}</p>
11 {% else %}
12 <p>{{ error }}</p>
13 {% endif %}
14</body>
15</html>
5. Настройка маршрута для отображения данных о погоде
Обновите index.php, чтобы добавить маршрут для отображения данных о погоде на странице.
1$app->get('/weather/{city}', function (Request $request, Response $response, $args) use ($twig) {
2 $city = $args['city'];
3 $apiKey = $_ENV['WEATHER_API_KEY'];
4 $url = "http://api.openweathermap.org/data/2.5/weather?q={$city}&appid={$apiKey}&units=metric";
5
6 $client = new \GuzzleHttp\Client();
7 try {
8 $apiResponse = $client->get($url);
9 $data = json_decode($apiResponse->getBody(), true);
10 return $twig->render($response, 'weather.twig', [
11 'city' => $city,
12 'weather' => $data
13 ]);
14 } catch (\Exception $e) {
15 return $twig->render($response, 'weather.twig', [
16 'city' => $city,
17 'error' => 'Unable to fetch weather data'
18 ]);
19 }
20});
6. Тестирование интеграции с внешним API
Теперь, когда все маршруты и шаблоны настроены, вы можете протестировать интеграцию с внешним API.
- Откройте браузер и перейдите по адресу
http://localhost:8080/weather/London, чтобы увидеть текущую погоду в Лондоне.
9. Интеграция с API Nominatim
1. Настройка конфигурации Slim
Обновите файл index.php, чтобы добавить маршруты для получения координат города с использованием API Nominatim и получения данных о погоде с использованием API OpenWeatherMap.
1<?php
2use Psr\Http\Message\ResponseInterface as Response;
3use Psr\Http\Message\ServerRequestInterface as Request;
4use Slim\Factory\AppFactory;
5use DI\Container;
6use Dotenv\Dotenv;
7use Slim\Middleware\SessionMiddleware;
8
9require __DIR__ . '/../vendor/autoload.php';
10
11// Загрузка переменных окружения
12$dotenv = Dotenv::createImmutable(__DIR__ . '/..');
13$dotenv->load();
14
15$container = new Container();
16AppFactory::setContainer($container);
17
18$container->set('db', function() {
19 $host = $_ENV['DB_HOST'];
20 $db = $_ENV['DB_NAME'];
21 $user = $_ENV['DB_USER'];
22 $pass = $_ENV['DB_PASS'];
23 $charset = 'utf8mb4';
24
25 $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
26 $options = [
27 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
28 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
29 PDO::ATTR_EMULATE_PREPARES => false,
30 ];
31
32 try {
33 return new PDO($dsn, $user, $pass, $options);
34 } catch (\PDOException $e) {
35 throw new \PDOException($e->getMessage(), (int)$e->getCode());
36 }
37});
38
39$app = AppFactory::create();
40$app->add(SessionMiddleware::class);
41
42// Маршруты регистрации и авторизации (как было описано ранее)
43
44// Получение данных о погоде с использованием API Nominatim и OpenWeatherMap
45$app->get('/weather/{city}', function (Request $request, Response $response, $args) {
46 $city = $args['city'];
47 $weatherApiKey = $_ENV['WEATHER_API_KEY'];
48 $nominatimUrl = "https://nominatim.openstreetmap.org/search?q={$city}&format=json&limit=1";
49
50 $client = new \GuzzleHttp\Client();
51 try {
52 // Запрос к Nominatim API для получения координат города
53 $nominatimResponse = $client->get($nominatimUrl);
54 $locationData = json_decode($nominatimResponse->getBody(), true);
55
56 if (empty($locationData)) {
57 $response->getBody()->write(json_encode(['error' => 'City not found']));
58 return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
59 }
60
61 $latitude = $locationData[0]['lat'];
62 $longitude = $locationData[0]['lon'];
63
64 // Запрос к OpenWeatherMap API для получения данных о погоде по координатам
65 $weatherUrl = "http://api.openweathermap.org/data/2.5/weather?lat={$latitude}&lon={$longitude}&appid={$weatherApiKey}&units=metric";
66 $weatherResponse = $client->get($weatherUrl);
67 $weatherData = json_decode($weatherResponse->getBody(), true);
68
69 $response->getBody()->write(json_encode($weatherData));
70 return $response->withHeader('Content-Type', 'application/json');
71 } catch (\Exception $e) {
72 $response->getBody()->write(json_encode(['error' => 'Unable to fetch weather data']));
73 return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
74 }
75});
76
77$app->run();
2. Тестирование интеграции с внешним API
Теперь, когда все маршруты и шаблоны настроены, вы можете протестировать интеграцию с внешним API.
- Откройте браузер и перейдите по адресу
http://localhost:8080/weather/London, чтобы увидеть текущую погоду в Лондоне.