- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих
Шрифт:
Интервал:
Закладка:
Преобразователь определяет тип, в который он должен десериализоваться, на основе ограничения типа соответствующего параметра метода. Если этот тип не включает JSON::Serializable или ASR::Serializable, выдается ошибка времени компиляции. Мы можем подтвердить, что все еще работает, сделав еще один запрос, подобный предыдущему, и утверждая, что мы получили тот же ответ, что и раньше.
Однако есть проблема с этой реализацией. Наш API в настоящее время с радостью принимает пустые значения как для свойств заголовка, так и для тела. Вероятно, нам следует предотвратить это, проверив тело запроса, чтобы мы могли быть уверены в его корректности к тому моменту, когда оно дойдет до действия контроллера. К счастью для нас, мы можем использовать компонент Validator Athena.
Проверка
Компонент Athena Validator — это надежная и гибкая среда для проверки как объектов, так и значений. Его основной API предполагает применение аннотаций, представляющих ограничения, которые вы хотите проверить. Экземпляр этого объекта затем может быть проверен с помощью экземпляра валидатора, который вернет, возможно, пустой список нарушений. У компонента слишком много функций, чтобы их можно было охватить в этой главе, поэтому мы сосредоточимся на том, что необходимо для проверки наших статей. См. https://athenaframework.org/Validator/ для получения дополнительной информации.
Что касается наших статей, то главное, чего мы хотим избежать, — это пустые значения. Мы также можем ввести требования к минимальной и максимальной длине, гарантируя, что они не содержат определенных слов или фраз или чего-либо еще, что вы захотите сделать. В любом случае, первое, что нужно сделать, — это включить AVD::Validatable в наш тип Article. Отсюда мы можем затем применить ограничение NotBlank к заголовку и телу, добавив аннотацию @[Assert::NotBlank], например:
@[Assert::NotBlank]
property title : String
@[Assert::NotBlank]
property body : String
Если вы попытаетесь использовать пустые значения POST, будет возвращен ответ об ошибке 422, в котором будут указаны нарушения и свойство, к которому они относятся. UUID кода ошибки — это машиночитаемое представление конкретного нарушения, которое можно использовать для проверки определенных ошибок без необходимости анализа сообщения, которое можно настроить, например:
{
"code": 422,
"message": "Validation failed",
"errors": [
{
"property": "body",
"message": "This value should not be blank.",
"code": "0d0c3254-3642-4cb0-9882-46ee5918e6e3"
}
]
}
Это работает «из коробки», поскольку ATH::RequestBodyConverter проверит, является ли десериализованный объект проверяемым после его десериализации, и проверит его, если это так. Компонент валидатора имеет множество ограничений, но также можно определить собственные. См. https://athenaframework.org/Validator/Constraints/ и https://athenaframework.org/comComponents/validator/#custom-constraints для получения дополнительной информации соответственно.
Следующим в списке вопросов, на которые следует обратить внимание, является то, что в настоящее время наша конечная точка для создания статьи по сути просто возвращает то, что ей было предоставлено. Чтобы можно было просмотреть все статьи, нам нужно настроить возможность сохранения их в базе данных.
Реализация взаимодействия с базой данных
Любому приложению, которому необходимо сохранять данные, чтобы их можно было получить позже, необходима база данных той или иной формы. Наш блог ничем не отличается, поскольку нам понадобится способ хранения статей, составляющих блог. Существуют различные типы баз данных, такие как NoSQL или реляционные и другие, каждая из которых имеет свои плюсы и минусы. В нашем блоге мы собираемся упростить задачу и использовать реляционную базу данных, такую как MySQL или PostgreSQL. Не стесняйтесь использовать базу данных по вашему выбору, которая лучше всего соответствует потребностям вашего приложения, но для целей этой главы я буду использовать PostgreSQL.
Настройка базы данных
Crystal предоставляет сегмент абстракции базы данных https://github.com/crystallang/crystal-db, который определяет высокоуровневый API для взаимодействия с базой данных. Каждая реализация базы данных использует это в качестве основы и реализует способ получения данных из базового хранилища. Это обеспечивает унифицированный API и общие функции, которые могут использовать все реализации баз данных. В нашем случае мы можем использовать https://github.com/will/crystal-pg для взаимодействия с нашей базой данных PG.
Давайте начнем с добавления этой зависимости в раздел зависимостей shard.yml, который теперь должен выглядеть следующим образом:
dependencies:
athena:
github: athena-framework/framework
version: ~> 0.16.0
pg:
github: will/crystal-pg
version: ~> 0.26.0
Обязательно запустите shards install еще раз и добавьте require "pg" в src/blog.cr. При этом будет установлен сегмент абстракции базы данных Crystal вместе с драйвером для Postgres. Crystal также имеет несколько ORM, которые можно использовать для простого взаимодействия с базой данных. Однако для наших целей я собираюсь просто использовать абстракции базы данных по умолчанию, чтобы упростить задачу. ORM, по сути, являются обертками того, что предоставляется драйвером, поэтому полезно иметь представление о том, как они работают под капотом.
Базовый сегмент абстракции предоставляет модуль DB::Serializable, который мы можем использовать это, чтобы немного облегчить себе жизнь. Этот модуль работает аналогично JSON::Serializable, но для запросов к базе данных, что позволяет нам создавать экземпляр нашего типа из сделанного нами запроса. Стоит отметить, что этот модуль не сохраняет экземпляр в базу данных, а только читает из нее. Поэтому нам придется справиться с этим самостоятельно или, возможно, даже реализовать некоторые из наших собственных абстракций.
Прежде чем мы приступим к настройке регистрации пользователей, нам необходимо настроить базу данных. Есть несколько способов сделать это, но самый простой, который я нашел, — это использовать docker-compose, который позволит нам развернуть сервер Postgres, которым будет легко управлять, и при необходимости его можно будет отключить. Файл compose, который я использую, выглядит следующим образом:
version: '3.8'
services:
pg:
image: postgres:14-alpine
container_name: pg
ports:
- "5432:5432"
environment:
- POSTGRES_USER=blog_user
- POSTGRES_PASSWORD=mYAw3s0meB!log
volumes:
- pg-data:/var/lib/postgresql/data
- ./db:/migrations
volumes:
pg-data:
Хотя я не буду вдаваться в подробности, суть в том, что мы определяем контейнер pg, который будет использовать Postgres 14, доступный через порт по умолчанию, используя переменные среды для настройки пользователя и базы данных. и, наконец, создание тома, который позволит данным сохраняться между его запуском и выключением. Мы также добавляем папку db/ в качестве тома. Это сделано