"application/ json"}
)
end
end
Здесь мы определяем наш класс контроллера, обязательно наследуя от ATH::Controller. При желании можно использовать пользовательские классы абстрактных контроллеров, чтобы обеспечить общую вспомогательную логику для всех экземпляров контроллера. Затем мы определили метод экземпляра #create_article, который возвращает ATH::Response. К этому методу применена аннотация ARTA::Post, которая указывает, что эта конечная точка является конечной точкой POST, а также путь, по которому должно обрабатываться это действие контроллера. Что касается тела метода, мы создаем экземпляр и преобразуем жестко закодированный экземпляр нашего объекта статьи в JSON, чтобы использовать его в качестве тела нашего ответа. Мы также устанавливаем заголовок типа контента ответа. Отсюда давайте подключим все и убедимся, что все работает как положено.
Возвращаясь к первоначально созданному файлу src/blog.cr, замените все его текущее содержимое следующим:
require "json"
require "athena"
require "./controllers/*"
require "./entities/*"
module Blog
VERSION = "0.1.0"
module Controllers; end
module Entities; end
end
Здесь нам просто нужна Athena, модуль JSON Crystal, а также папки контроллера и сущностей. Мы также определили здесь пространства имен Controllers и Entities, чтобы в будущем к ним можно было добавлять документацию.
Далее давайте создадим еще один файл, который будет служить точкой входа в наш блог, скажем, src/server.cr со следующим содержимым:
require "./blog"
ATH.run
Такой подход гарантирует, что сервер не запустится автоматически, если мы просто хотим запросить исходный код где-то еще, например, в нашем коде спецификации. ATH.run по умолчанию запустит наш сервер Athena на порту 3000.
Теперь, когда сервер запущен, если бы мы выполнили следующий запрос, используя cURL, например, curl --request POST 'http://localhost:3000/article', мы получили бы следующий ответ, как ожидал:
{
"title": "Title",
"body": "Body"
}
Однако, поскольку мы хотим, чтобы наш API возвращал JSON, есть более простой способ сделать это. Мы можем обновить действие нашего контроллера, чтобы напрямую возвращать экземпляр нашего объекта статьи. Афина позаботится о его преобразовании в JSON и настройке необходимых заголовков. Теперь метод выглядит так:
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/.