Роутер
Напишите древовидную библиотеку, повысьте навыки работы с деревьями и научитесь улучшать скорость работы алгоритма.
Цель
Роутер — проект, в котором мы прокачаем работу с древовидными структурами. Эта тема изучалась на курсе по деревьям, а здесь она раскрывается на задаче, которую решают современные фреймворки. В ходе разработки мы создадим абстракцию, чтобы удобно обходить дерево и накапливать результаты работы.
Архитектура
Роутер — один из самых используемых компонентов на любом сайте, через который на него обращаются. От производительности роутера зависит как быстро будет работать сайт. Например, если на нагруженный ресурс поступает тысячи запросов в секунду и есть много маршрутов, то он может загружаться существенное время. Поэтому здесь важны устройство и скорость роутера.
Чтобы он работал эффективно, разработчики используют специальные структуры данных, например, выражают внутреннюю структуру в виде префиксного дерева.
Описание
У каждой страницы сайта есть URL-адрес. Когда мы обращаемся к сайту, движок, на котором он написан, анализирует URL-адрес и пытается найти функцию, чтобы сгенерировать ответ. За этот процесс отвечает роутинг, который реализован в виде отдельного компонента — роутера. Он выбирает функцию в зависимости от URL-адреса.
Роутеры часто реализуются в виде отдельных библиотек, которые потом используются внутри сайта. Это хорошая практика, и в этом проекте мы напишем такую библиотеку. В итоге наш роутер можно будет использовать на реальных сайтах.
Пример реальной библиотеки в языке JavaScript:
// https://adonisjs.com/docs/4.1/routing
// Определение маршрута /
// Вторым параметром передается обработчик
// Он просто возвращает строку Hello Hexlet
Route.get('/', () => 'Hello Hexlet');
// Определение маршрута /about
Route.get('/about', () => 'About Hexlet');
// Где-то запускаем сайт example.com
// и делаем запрос
curl example.com
Hello Hexlet
curl example.com/about
About Hexlet
Пример использования нашей библиотеки:
import serve from '@hexlet/code';
const routes = [
{
path: '/hello', // маршрут
method: 'POST', // метод HTTP
handler: { // обработчик
body: 'Hello!'
},
},
{
path: '/hello/:name', // динамический маршрут
handler: {
body: 'Hello Friend!'
},
constraints: { name: '\\w+' }, // ограничения, накладываемые на динамический маршрут
},
];
// Запрос из сети
// На самом деле, всё гораздо сложнее и в реальности сам HTTP запрос обрабатывает сервер на сайте
// Далее он сам прокидывает запрос в роутер
// Мы просто говорим, что запрос должен состоять из пути и метода
const request = { path: 'hello/Hexlet', method: 'GET' };
// Вызываем наш роутер, передаем ему роуты и запрос из "сети"
const result = serve(routes, request);
// { path: 'hello/Hexlet', method: 'GET', handler: { body: Hello Friend! }, params: { name: 'Hexlet' } }
// "Вызываем" обработчик, который вернул роутер
result.handler.body; // Hello Friend!
PHP
use function Hexlet\Code\serve;
$routes = [
[
'path' => '/hello',
'method' => 'POST',
'handler' => ['body' => 'Hello!'],
],
[
'path' => '/hello/:name',
'method' => 'GET',
'handler' => ['body' => 'Hello Friend!'],
'constraints' => ['name' => '\w+'],
],
];
$request = ['path' => 'hello/Hexlet', 'method' => 'GET'];
$result = serve($routes, $request);
if ($result) {
echo $result['handler']['body']; // Hello Friend!
} else {
echo 'Route not found';
}
Java
List<Map<String, Object>> routes = List.of(
Map.of(
"method", "POST", // метод HTTP
"path", "/hello", // маршрут
"handler", Map.of("body", "Hellp!") // обработчик
),
Map.of(
"path", "/hello/:name", // динамический маршрут
"handler", Map.of("body", "Hello Friend!"),
"constraints", Map.of("name", "\\w+") // ограничения, накладываемые на динамический маршрут
)
);
// Запрос "из сети"
// На самом деле, всё гораздо сложнее и в реальности сам HTTP запрос обрабатывает сервер на сайте
// Далее он сам прокидывает запрос в роутер
// Мы просто говорим, что запрос должен состоять из пути и метода
Map<String, String> request = Map.of("path", "hello/Hexlet", "method", "GET");
// Вызываем наш роутер, передаем ему роуты и запрос из "сети"
Map<String, Object> result = Router.serve(routes, request);
// {handler={body=Hello Friend!}, path=hello/Hexlet, method=GET, params={name=Hexlet}}
// "Вызываем" обработчик, который вернул роутер
var handler = (Map) result.get("handler");
var body = handler.get("body"); // Hello Friend!
Данный проект пока доступен на JavaScript, PHP и Java. Поддержка других языков добавится позже
Проекты входят в стоимость обучения на любом плане: самостоятельном, групповом и индивидуальном. Дополнительно платить не нужно.
Проекты дают опыт разработки в реальной среде. Проходите каждый проект сразу после изучения курсов, которые стоят в учебном плане перед ним, — это отличный способ глубже разобраться в материале.
Проекты — портфолио программиста. Их код останется в вашем аккаунте на GitHub и будет преимуществом при поиске работы.
Чтобы узнать о том, что такое проекты и в чём их польза, прочитайте нашу статью «Анатомия проектов Хекслета».
Задавайте вопросы в разделе «Обсуждение» на странице шага, на котором возникли трудности, или вашему наставнику. Изучите вопросы других студентов в «Обсуждениях»: там собрана большая база знаний, ей можно и нужно пользоваться.
Автоматизированные тесты и линтер. В групповом и индивидуальном форматах наставник дополнительно проверит то, что тестами проверить невозможно (архитектуру проекта, правильность именования, удачность решений), и проведёт код-ревью, чтобы сделать проект ещё качественнее.
Нажмите на виджет в правом нижнем углу экрана и поищите ответ в нашей справке. Или сразу пишите на support@hexlet.io — вам ответит живой человек из команды Хекслета.