Декораторы¶
Одной из заманчивых возможностей приложений на базе WSGI является использование middleware-прослоек. Для RESTAS аналогичные возможности предоставляют декораторы. Данная возможность основана на использовании класса routes:proxy-route для создания обёрток над маршрутами и переопределения их поведения с помощью специализации соответствующих generic-методов.
Декоратор - функция, которая принимает маршрут и возвращает другой. Например, для запрета кэширования браузерами результатов HTTP-запросов можно использовать такой декоратор:
(defmethod process-route :before ((route no-cache-route) bindings)
(setf (hunchentoot:header-out :expires)
(hunchentoot:rfc-1123-date))
(setf (hunchentoot:header-out :cache-control)
"max-age=0, no-store, no-cache, must-revalidate"))
(defun @no-cache (route)
(make-instance 'no-cache-route :target route))
Теперь можно использовать данный декоратор при определении маршрута:
"<h1>Hello world!</h1>")
Либо, его можно применить к модулю целиком
(:use :cl)
(:decorators #'restas:@no-caсhe))
Или даже при подключении субмодуля:
Все маршруты, определённые с помощью restas:define-route, перед помещение в дерево диспетчеризации пропускаются через последовательность декораторов. В первую очередь для обработки маршрута используются декораторы указанные в restas:define-route, затем декораторы указанные в restas:define-module и наконец декораторы указанные в restas:mount-submodule. Таким образом, в дерево помещается не оригинальный объект класса restas:route, а цепочка вложенных друг в друга прокси-объектов.
Определение нового декоратора состоит из определения класса, наследующего от routes:proxy-route, специализации для него одного или нескольких generic-методов и определении функции для создания объектов этого класса из оригинальных объектов.
При определении подобным образом новых классов маршрутов имеет смысл специализировать следующие методы:
routes:route-check-conditions (route bindings) - вызывается после того, как шаблон URL маршрута будет сопоставлен URL-запроса и позволяет определить дополнительные ограничения. Если возвращается T, то маршрут считается удовлетворяющим запросу, в случае NIL маршрут отбрасывается и система переходит к рассмотрению следующего.
restas:process-route (route bindings) - вызывается для реальной обработки запроса.
Декораторы можно использовать, например, для:
Аутентификации/авторизации
Тонкой настройки заголовков ответа
Настройки окружения, в котором будет происходить обработка запроса
Ниже тривиальный пример использования декоратора для требования HTTP-аутентификации при просмотре содержимого директории, опубликованного с помощью модуля restas-directory-publisher.
(defmethod routes:route-check-conditions ((route http-auth-route) bindings)
(and (call-next-method)
(multiple-value-bind (user password) (hunchentoot:authorization)
(or (and (string= user "hello")
(string= password "world"))
(hunchentoot:require-authorization)))))
(defun @http-auth-require (route)
(make-instance 'http-auth-route :target route))
(restas:mount-submodule -tmp- (#:restas.directory-publisher @http-auth-require)
(restas.directory-publisher:*baseurl* '("tmp"))
(restas.directory-publisher:*directory* #P"/tmp/")
(restas.directory-publisher:*autoindex* t))