include Athena::Framework::View::FormatHandlerInterface
private CRINJA = Crinja.new loader: Crinja::Loader::
FileSystem
Loader.new "#{__DIR__}/../views"
def call(view_handler : ATH::View::ViewHandlerInterface, view
: ATH::ViewBase, request : ATH::Request, format : String) :
ATH::Response
ann_configs = request.action.annotation_configurations
unless template_ann = ann_configs[Blog::Annotations::
Template]?
raise "Unable to determine the template for the
'#{request.attributes.get "_route"}' route."
end
unless (data = view.data).is_a? Crinja::Object
raise ATH::Exceptions::NotAcceptable.new "Cannot convert value of type '#{view.data.class}' to '#{format}'."
end
content = CRINJA.get_template(template_ann.name). render({data: view.data})
ATH::Response.new content, headers: HTTP::Headers{"content- type" => "text/html"}
end
def format : String
"html"
end
end
Помимо выполнения некоторых вещей, с которыми мы уже должны быть знакомы, таких как регистрация службы и включение модуля интерфейса, мы также определяем метод #format
, который возвращает формат, который обрабатывает этот тип. Мы также создали одноэлементный экземпляр Crinja, который будет загружать шаблоны из папки #get_template
, поэтому нет необходимости перезапускать сервер, если вы только внесли изменения в шаблон. Однако в его нынешнем виде для этого потребуется, чтобы путь существовал и был действительным как в среде разработки, так и в производственной среде. Рассмотрите возможность использования переменной среды для указания пути.
Наконец, мы определили метод #call
, который имеет доступ к различной информации, которую можно частично использовать для обработки ответа. В нашем случае нам нужны только параметры view
и request
, последний из которых используется для получения всех конфигураций аннотаций, определенных на соответствующем маршруте. Здесь в игру вступает аннотация, которую мы создали ранее, поскольку мы можем проверить, применяется ли ее экземпляр к действию контроллера, связанному с текущим запросом. См. https://athenaframework.org/Framework/View/ для получения дополнительной информации о том, что отображается через эти параметры.
Далее мы обрабатываем некоторые контексты ошибок, например, если конечная точка не имеет аннотации шаблона или возвращаемое значение не может быть отображено через Crinja. Я намеренно создаю общие исключения, чтобы возвращался ответ об ошибке 500
, поскольку мы не хотим утечки внутренней информации за пределы API.
Наконец, мы используем Crinja для получения шаблона на основе имени в аннотации и его визуализации, используя значение, возвращаемое из действия контроллера, в качестве значения объекта данных. Затем мы используем визуализированное содержимое в качестве тела ответа для ATH::Response
, устанавливая тип содержимого ответа на
Чтобы включить такое поведение, нам просто нужно применить аннотацию @ [Blog::Annotations::Template("article.html.j2")]
к нашему методу #article
в ArticleController
. Мы можем все проверить, сделав еще один запрос:
curl --request GET 'http://localhost:3000/article/1' --header
'accept: text/html'
Ответом в этом контексте должен быть наш HTML-шаблон. Если вы установите заголовок
Резюме