- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Crystal Programming. Введение на основе проекта в создание эффективных, безопасных и читаемых веб-приложений и приложений CLI - Джордж Дитрих
Шрифт:
Интервал:
Закладка:
def create_article : Blog::Entities::Article
Blog::Entities::Article.new "Title", "Body"
end
Если вы отправите еще один запрос, вы увидите тот же ответ. Причина, по которой это работает, связана с Рис. 9.1, приведенным ранее в этой главе. Если действие контроллера возвращает ATH::Response, этот ответ возвращается клиенту в том виде, в каком он есть. Если возвращается что-то еще, генерируется событие просмотра, задачей которого является преобразование возвращаемого значения в ATH::Response.
Athena также предоставляет некоторые более специализированные подклассы ATH::Response. Например, ATH::RedirectResponse можно использовать для обработки перенаправлений, а ATH::StreamedResponse можно использовать для потоковой передачи данных клиенту посредством фрагментированного кодирования в тех случаях, когда в противном случае данные ответа были бы слишком большими, чтобы поместиться в памяти. Дополнительную информацию об этих подклассах см. в документации API: https://athenaframework.org/Framework/.
Предполагая, что наш API будет обслуживать отдельную базу кода внешнего интерфейса, нам нужно будет настроить CORS, чтобы внешний интерфейс мог получить доступ к данным. Athena поставляется в комплекте с прослушивателем, который его обрабатывает, и его нужно просто включить и настроить.
Чтобы все было организованно, давайте создадим новый файл src/config.cr и добавим следующий код, обязательно потребовав его и в src/blog.cr:
def ATH::Config::CORS.conРисунок : ATH::Config::CORS?
new(
allow_credentials: true,
allow_origin: ["*"],
)
end
В идеале значение источника должно быть фактическим доменом вашего приложения, например https://app.myblog.com. Однако в этой главе мы просто позволим все что угодно. Athena также поддерживает концепцию параметров, которые можно использовать для настройки независимо от окружающей среды. Дополнительную информацию см. на https://athenaframework.org/Components/config/.
Мы также используем не слишком широко известную функцию Crystal, чтобы сделать нашу логику настройки более краткой. Определению может быть присвоен префикс типа и точка перед именем метода в качестве ярлыка при определении метода класса для определенного типа. Например, предыдущий пример будет эквивалентен следующему:
struct ATH::Config::CORS
def self.conРисунок : ATH::Config::CORS?
new(
allow_credentials: true, allow_origin: ["*"],
)
end
end
Помимо того, что сокращенный синтаксис является более кратким, он устраняет необходимость выяснять, является ли тип структурой или классом. На этом этапе мы можем сделать запрос и получить обратно созданную статью, но, учитывая, что статья, возвращаемая из этой конечной точки, жестко запрограммирована, это бесполезно. Давайте проведем рефакторинг, чтобы мы могли создать статью на основе тела запроса.
Обработка тела запроса
Как мы видели ранее, поскольку мы включили JSON::Serializable в нашу сущность, мы можем преобразовать его в представление JSON. Мы также можем сделать обратное: создать экземпляр на основе строки JSON или I/O. Для этого мы можем обновить действие нашего контроллера, обновив его так:
def create_article(request : ATH::Request) :
Blog::Entities::Article
if !(body = request.body) || body.peek.try &.empty?
raise ATH::Exceptions::BadRequest.new "Request does not have a body."
end
Blog::Entities::Article.from_json body
end
Параметры действия контроллера, например параметры пути маршрута или запроса, передаются действию в качестве аргументов метода. Например, если путь действия был "/add/{val1}/{val2}", метод действия контроллера будет следующим: def add(val1 : Int32, val2 : Int32) : Int32, где разрешаются два добавляемых значения. из пути, преобразуются в ожидаемые типы и передаются методу. Аргументы действия также могут поступать из значений по умолчанию, аргументов типа ATH::Request или атрибутов запроса.
В этом примере мы используем типизированный параметр ATH::Request для получения доступа к телу запроса и его десериализации. Также технически возможно, что запрос не имеет тела, поэтому мы проверяем его существование, прежде чем продолжить, возвращая ответ об ошибке, если оно равно nil или если тело запроса отсутствует. Мы также выполняем десериализацию непосредственно из I/O тела запроса, поэтому не нужно создавать промежуточную строку, что приводит к более эффективному использованию памяти.
Обработка ошибок в Athena очень похожа на любую другую программу Crystal, поскольку для представления ошибок она использует исключения. Athena определяет набор общих типов исключений в пространстве имен ATH::Exceptions. Каждое из этих исключений наследуется от Athena::Exceptions::HTTPException, который представляет собой особый тип исключения, используемый для возврата ответов об ошибках HTTP. Например, если тела не было, оно будет возвращено клиенту с кодом состояния 400:
{
"code": 400,
"message": "Request does not have a body."
}
Базовый тип или дочерний тип также могут быть унаследованы для сбора дополнительных данных или добавления дополнительных функций. Любое возникающее исключение, не являющееся экземпляром Athena::Exceptions::HTTPException, рассматривается как внутренняя ошибка сервера 500. По умолчанию эти ответы об ошибках сериализуются в формате JSON, однако это поведение можно настроить. См. https://athenaframework.org/Framework/ErrorRendererInterface/ для получения дополнительной информации.
Теперь, когда мы убедились, что есть тело, мы можем продолжить и создать экземпляр нашей статьи, вернув тело Blog::Entities::Article.from_json. Если бы вы сделали тот же запрос, что и раньше, но с этой полезной нагрузкой, вы бы увидели, что все, что вы отправляете, вы получите обратно в ответ:
{
"title": "My Title",
"body": "My Body"
}
Соответствующая команда cURL будет выглядеть следующим образом:
curl --request POST 'http://localhost:3000/article'
--header 'Content-Type: application/json'
--data-raw '{
"title": "My Title",
"body": "My Body"
}'
Отлично! Но так же, как существовал лучший способ вернуть ответ, Athena предлагает довольно удобный способ упростить десериализацию тела ответа. У Athena есть уникальная концепция, называемая преобразователями параметров. Конвертеры параметров позволяют применять собственную логику для преобразования необработанных данных из запроса в более сложные типы. См. https://athenaframework. org/Framework/ParamConverter/ для получения дополнительной информации.
Примеры преобразователей параметров включают следующее:
• Преобразование строки даты и времени в экземпляр времени.
• Десериализация тела запроса в определенный тип.
• Преобразование параметра пути идентификатора пользователя в реальный экземпляр пользователя.
Athena предоставляет первые два в качестве встроенных преобразователей, но когда дело доходит до определения пользовательских конвертеров, нет предела. Давайте воспользуемся преобразователем параметров, чтобы упростить действие контроллера создания статьи. Обновите метод следующим образом:
@[ARTA::Post("/article")]
@[ATHA::ParamConverter("article", converter:
ATH::RequestBodyConverter)]
def create_article(article : Blog::Entities::Article) :
Blog::Entities::Article
article
end
Нам удалось сжать действие контроллера в одну строку! Основным нововведением здесь является аннотация ATHA::ParamConverter, а также обновление метода для приема экземпляра статьи вместо запроса. Первый позиционный аргумент в аннотации представляет, какой параметр действия