Перевод документации к Vibe.d. Часть 3.
Основываясь на низкоуровневой базе HTTP/HTML, высокоуровневая структура веб-приложений обеспечивает более быструю и надежную их разработку. Она использует декларативный подход, основанный на классах, для избегания повторов кода. Статическая типизация используется как можно больше для исключения ошибок преобразования, или ошибок доступа к неправильным ключам времени выполнения (например, несуществующее или ошибочное поле формы).
Фреймворк представлен в двух вариантах: один для «front end» разработки, нацеленный на создание HTML-страниц и запросов на обработку форм, а другой для разработки на основе REST, обеспечивающий прозрачный RPC-механизм на основе JSON / REST (клиент и сервер). Оба этих компонента имеют одинаковую основу и используют одну и ту же карту методов класса маршрутизации URLRouter.
В обычном случае оба метода HTTP и соответствующий путь выводятся из имени метода класса. В частности, имя сопоставляется определенному HTTP-методу в соответствии с его префиксом, а остальная часть имени преобразуется в имя пути в настраиваемом стиле. Кроме того, можно использовать @path и @method для переопределения этих значений по умолчанию.
Метод HTTP | Соответствующие префиксы |
GET | get, query, геттеры с @property, методы с именем index |
POST | post, create, add, без префикса |
PUT | put, set, сеттеры с @property |
PATCH | patch, update |
DELETE | delete, erase, remove |
Генератор веб-интерфейса
Генератор «front end» веб-интерфейса автоматически отображает входящие запросы или поля формы POST в параметры метода, автоматически выполняет необходимое преобразование и проверку. Кроме того, он предлагает несколько удобных функций для рендеринга шаблонов Diet, обработки сессий и выполнения перенаправления — без прямого доступа к базовому объекту HTTPServerRequest или HTTPServerResponse. В большинстве случаев это позволяет полностью статически проверять и очищать код.
В тех ситуациях, когда требуется больше контроля, можно просто объявить параметры типа HTTPServerRequest или HTTPServerResponse чтобы предоставить методу полный доступ. Обратите внимание, что это отличается от описанного ниже генератора интерфейса REST, который не может предоставить доступ к запросу / ответу, не теряя возможности генерировать клиентскую сторону протокола REST. Однако он обеспечивает способ обойти это, используя атрибут @before.
Пример: source/app.d
import vibe.http.router; import vibe.http.server; import vibe.web.web; shared static this() { auto router = new URLRouter; router.registerWebInterface(new WebInterface); auto settings = new HTTPServerSettings; settings.port = 8080; settings.sessionStore = new MemorySessionStore; listenHTTP(settings, router); } class WebInterface { private { // хранится в хранилище сессий SessionVar!(bool, "authenticated") ms_authenticated; } // GET / void index() { bool authenticated = ms_authenticated; render!("index.dt", authenticated); } // POST /login (имя пользователя и пароль автоматически считываются как поля формы) void postLogin(string username, string password) { enforceHTTP(username == "user" && password == "secret", HTTPStatus.forbidden, "Invalid user name or password."); ms_authenticated = true; redirect("/"); } // POST /logout @method(HTTPMethod.POST) @path("logout") void postLogout() { ms_authenticated = false; terminateSession(); redirect("/"); } }
Локализация
Используя файлы переводов, совместимые с GNU gettext, вы можете локализовать шаблоны Diet во время компиляции. Для этого просто нужно поместить файлы перевода с помощью схемы именования <name>.<language>.po в путь, который зарегистрирован в поле «stringImportPaths» файла dub.json. <language> должен быть идентификатором языка формы en_US.
Пример: source/app.d
import vibe.web.web; struct TranslationContext { alias languages = TypeTuple!("en_US", "ru_RU"); mixin translationModule!"example"; } @translationContext!TranslationContext class WebInterface { void index() { render!("index.dt"); } }
Пример: views/index.dt
doctype 5 html head title& Welcome body h1& Welcome p& home.welcome.text
Пример: translations/example.en_US.po
msgid "Welcome" msgstr "Welcome" msgid "home.welcome-text" msgstr "Hello, this is a translation example."
Пример: translations/example.ru_RU.po
msgid "Welcome" msgstr "Добро пожаловать" msgid "home.welcome-text" msgstr "Привет, это пример локализации."
Генератор REST-интерфейса
Подобно генератору веб-интерфейса, ориентированному на браузер, существует ориентированный на машины JSON / REST генератор интерфейса. Параметры метода сопоставляются с полями JSON и сериализуются в соответствии с обычными правилами сериализации. В дополнение к генератору интерфейса существует также клиентский генератор, который автоматически реализует класс, совершающий надлежащие REST-вызовы для доступа к REST-интерфейсу.
import vibe.core.core; import vibe.core.log; import vibe.http.router; import vibe.http.server; import vibe.web.rest; struct Weather { string text; double temperature; // °C } interface MyAPI { // GET /weather -> отвечает {"text": "...", "temperature": ...} Weather getWeather(); // PUT /location -> accepts {"location": "..."} @property void location(string location); // GET /location -> отвечает "..." @property string location(); } class MyAPIImplementation : MyAPI { private { string m_location; } Weather getWeather() { return Weather("sunny", 25); } @property void location(string location) { m_location = location; } @property string location() { return m_location; } } shared static this() { auto router = new URLRouter; router.registerRestInterface(new MyAPIImplementation); auto settings = new HTTPServerSettings; settings.port = 8080; listenHTTP(settings, router); // создаем клиент для взаимодействия с API через REST-интерфейс runTask({ auto client = new RestInterfaceClient!MyAPI("http://127.0.0.1:8080/"); auto weather = client.getWeather(); logInfo("Weather: %s, %s °C", weather.text, weather.temperature); client.location = "Moscow"; logInfo("Location: %s", client.location); }); }