- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих
Шрифт:
Интервал:
Закладка:
Если объект с предоставленным идентификатором не найден, мы возвращаем ответ об ошибке 404.
Последняя ключевая часть того, как это работает, относится к ранее в главе, когда мы изучали, как Athena предоставляет аргументы для каждого действия контроллера. Одним из таких способов разрешения аргументов является использование атрибутов запроса, которые можно рассматривать как хранилище ключей/значений для произвольных данных, связанных с запросом, к которым автоматически добавляются параметры пути и запроса.
В контексте нашего конвертера метод configuration.name представляет имя параметра действия, к которому относится конвертер, на основе значения, указанного в аннотации. Мы используем это, чтобы установить имя атрибута, например, article, для разрешенного объекта. Затем Athena увидит, что это действие контроллера имеет параметр с именем article, проверит, существует ли атрибут с таким именем, и предоставит его действию, если он существует. Используя этот конвертер, мы можем обновить действие #article следующим образом:
@[ARTA::Get("/article/{id}")]
@[ATHA::ParamConverter("article", converter:
Blog::Converters::Database)]
def article(article : Blog::Entities::Article) :
Blog::Entities::Article
article
end
Та-да! Простой способ предоставления объектов базы данных непосредственно в качестве аргументов действия через их идентификаторы. Хотя на данный момент у нас уже довольно много конечных точек, связанных со статьями, нам все еще не хватает способа обновить или удалить статью. Давайте сначала сосредоточимся на том, как обновить статью.
Обновление статьи
На первый взгляд обновление записей базы данных может показаться простым, но на самом деле оно может быть довольно сложным из-за характера процесса. Например, чтобы обновить сущность, сначала необходимо получить ее текущий экземпляр, а затем применить к нему изменения. Изменения обычно представляются в виде тела запроса к конечной точке PUT с включенным идентификатором объекта, в отличие от конечной точки POST. Проблема заключается в том, как применить изменения из нового тела запроса к существующей сущности.
Сериализатор Athena имеет концепцию конструкторов объектов, которые управляют тем, как сначала инициализируется десериализуемый объект. По умолчанию они создаются обычным способом с помощью метода .new. Он предлагает возможность определять собственные объекты, что мы могли бы сделать, чтобы получить объект из базы данных на основе свойства ID в теле запроса. Затем мы применим остальную часть тела запроса к полученной записи. Это гарантирует правильную обработку скрытых значений базы данных, а также выполнение сложной части применения изменений к объекту.
Однако, поскольку это немного усложняет работу сериализатора Athena, а в нашей статье есть только два свойства, мы не собираемся это реализовывать. Если вам интересно, как это будет выглядеть, или вы хотите попробовать реализовать это самостоятельно, ознакомьтесь с рецептом кулинарной книги: https://athenaframework.org/cookbook/object_constructors/#db. Он использует Granite ORM, но переключить его на наш EntityManager должно быть довольно просто.
Вместо использования конструктора объекта мы просто собираемся вручную сопоставить значения из тела запроса и применить их к объекту, полученному из базы данных. Прежде чем мы сможем это сделать, нам сначала нужно обновить менеджер сущностей для обработки обновлений. Первым шагом является обновление #persist, чтобы проверить, установлен ли идентификатор с помощью следующего:
def persist(entity : DB::Serializable) : Nil
entity.before_save if entity.responds_to? :before_save
if entity.id?.nil?
entity.after_save self.save entity
else
self.update entity
end
Где метод #update выглядит следующим образом:
private def update(entity : Blog::Entities::Article) : Nil
@@connection.exec(
%(UPDATE "articles" SET "title" = $1, "body" = $2,
"updated_at" = $3, "deleted_at" = $4 WHERE "id" = $5;),
entity.title,
entity.body,
entity.updated_at,
entity.deleted_at,
entity.id
)
end
Отсюда мы можем обновить нашу конечную точку #update_article, чтобы она выглядела следующим образом:
@[ARTA::Put("/article/{id}")] @[ATHA::ParamConverter("article_entity", converter:
Blog::Converters::Database)]
@[ATHA::ParamConverter("article", converter:
ATH::RequestBodyConverter)]
def update_article(article_entity : Blog::Entities::Article,
article : Blog::Entities::Article) : Blog::Entities::Article
article_entity.title = article.title
article_entity.body = article.body
@entity_manager.persist article_entity
article_entity
end
В этом примере мы используем два преобразователя параметров. Первый извлекает реальную сущность статьи из базы данных, а второй создает ее на основе тела запроса. Затем мы применяем статью тела запроса к сущности статьи и передаем ее в #persist. Допустим, мы делаем такой запрос:
curl --request PUT 'http://localhost:3000/article/1' --header 'Content-Type: application/json'
--data-raw '{
"title": "New Title",
"body": "New Body",
"updated_at": "2022-04-09T05:13:30Z",
"created_at": "2022-04-09T04:47:09Z"
}'
Это приведет к такому ответу:
{
"id": 1, "title": "New Title",
"body": "New Body",
"updated_at": "2022-04-09T05:22:44Z",
"created_at": "2022-04-09T04:47:09Z"
}
Прекрасно! title, body, и updated_at были обновлены, как и ожидалось, тогда как временные метки id и create_at из базы данных не были изменены.
И последнее, но не менее важное: нам нужна возможность удалить статью.
Удаление статьи
Мы можем обрабатывать удаления, еще раз обновив наш менеджер сущностей, включив в него метод #remove, а также метод #on_remove для наших сущностей, который будет обрабатывать настройку свойства delete_at. Затем мы могли бы использовать преобразователь параметров базы данных на конечной точке DELETE и просто предоставить #remove разрешенному объекту.
Начните с добавления этого в менеджер сущностей:
def remove(entity : DB::Serializable) : Nil
entity.on_remove if entity.responds_to? :on_remove
self.update entity
end
А это к нашей статье:
protected def on_remove : Nil
@deleted_at = Time.utc
end
Наконец, действие контроллера будет выглядеть так:
@[ARTA::Delete("/article/{id}")]
@[ATHA::ParamConverter("article", converter:
Blog::Converters::Database)]
def delete_article(article : Blog::Entities::Article) : Nil
@entity_manager.remove article
end
Затем мы могли бы сделать запрос, например, curl --request DELETE 'http:// localhost:3000/article/1' и увидеть в базе данных, что столбец delete_at установлен. Потому что метод #find? также отфильтровывает удаленные элементы, поэтому попытка удалить ту же статью еще раз приведет к ошибке 404.
В некоторых случаях API может потребоваться поддержка возврата не только JSON. Athena предоставляет несколько способов улучшить согласование контента, обрабатывая несколько форматов ответов с помощью единственного возвращаемого значения из действия контроллера. Давайте взглянем.
Использование переговоров по содержанию
На данный момент наш блог действительно собирается вместе. Мы можем создавать, получать, обновлять и удалять статьи. У нас также есть несколько довольно надежных