March 11th, 2010

glider

Экспоз данных по REST - продолжение темы

Месяц назад я поднимал топик разработки веб-приложения в стиле "вся логика в JS, а на сервере всего лишь голые данные, которые экспозятся по ресту". Раньше я этот топик знал лишь в теории, а тогда выдался шанс попробовать все на практике - тем более, что проектик был совсем небольшой и, соответственно, риски мизерные.

В итоге оказалось все действительно круто и интересно - особенно придумывать все самому. На удивление, HTTP может выразить очень дофига семантики, которую обычно надо дизайнить самому. Например, возникло требование локализации контента экспозаемых данных - пожалуйста, вот вам Accept-Language. Хотите кэширование - нате вам етаги, ласт-модифаед и вообще всю инфраструктуру WWW (на эту тему читаем потс Уди Дахана "Building Super-Scalable Web Systems with REST". Даже идея попинговывать ресурсы (сервер, аппликуху, конкретную сущность модели данных) решается в рамках семантики HTTP - вбросом OPTIONS на нужный урл.

Из смешанных впечатлений - необходимость руками строить всю инфраструктуру и разбираться с противными мелочами вроде "а почему это я сервисы перебилдил, и в браузере F5 нажал, а данные все равно не приходят?!". Отдельной песней была необходимость ваять интерфас на чистом HTML+JS. Эта тема для меня очень новая, поэтому, подозреваю, что многие решения были, гхм, субоптимальными. Ну и, наконец, все эти RPC-штучки, вроде описанных в рядом лежащем посте оказались тупо не нужны - всю безумную логику сериализации и десериализации, которую я писал пару дней, пришлось за ненадобностью выкинуть (ну и слава Богу, ибо уровень сложности там оказался весьма неиллюзорным).

В конце февраля удалось расширить эксперимент в рамках настоящего проекта. Это еще не гигантский и бездушный монстр из кровавого энтерпрайза, но уже и не игрушечный вебпартик. Штук десять сущностей модели данных, столько же формочек и часов пицот грязного времени. Собственно с этим и связан сегодняшний рассказ.

***

Изрядно наколовшись на изобретении своего велосипеда в случае с вебпартом, в реальном проекте я решил заюзать уже существующие солюшены и обратил взгляд на Асторию (линка ведет не на абстрактный сайт, а на документ на три экрана, в котором мало букаф и многа примеров, кому после прочтения еще интересны детали - можно зачитать статейку "Using Microsoft ADO.NET Data Services").

С прошлого моего знакомства с Асторией, ситуация неслабо развилась. Протокол, по которому экспозятся данные, получил название OData и был заспецифицирован в гигантском документе. Инфраструктура вокруг провайдера данных была отделена от Entity Framework и оформлена в виде фреймворка (по ссылке заглавный потс серии про использование на практике). Приятно посмотреть.

В целом, Астория обеспечивает вот такой вот воркфлоу работы с данными приложения.
  1) Имеем датасорс (откуда он взялся и как он работает - в данном контексте неважно).
  2) Пишем для него адаптер или юзаем один из существующих адаптеров: для EF, для SharePoint и т. п. (свой адаптер написать реально несложно, кому интересно - см. серию статей, слинкованную выше).
  3) Получаем веб-сервис, к которому можно обращаться за данными по рест-протоколу OData.

Геты в OData выглядят вот так: http://myserver/data.svc/Customers(‘ALFKI’)/Orders?$filter=Active eq true and (year(OrderDate) eq 2007)$expand=Products (если что, детали в статье "Addressing Resources (ADO.NET Data Services)"). Данные приходят в JSON или в XML (в атом-фиде). Поддерживаются лейзи-ссылки и лейзи-коллекции (в JSON это тупо пустые объекты с единственным свойством "__deferred", в XML это <link rel="...">...</link>). CUD-операции выполняются через POST и DELETE (детали в статье: "Making Changes to Data (ADO.NET Data Services)". Поддерживается батчинг операций чтения и записи. Есть вроде и простенькая схема прав на глаголы и на данные, но я в детали не вдавался.

Последней каплей стало осознание того, что вокруг всего этого накручена неплохая экосистема: 1) однокликовая интеграция с моделью Entity Framework, 2) однокликовая генерация клиентских сервисов, к которым можно делать строго типизированные LINQ запросы, 3) вроде даже подружили Асторию и MS AJAX, 4) кроме того, сама Астория уже существует года два, поэтому я буду далеко не первым, кто будет собирать в ней грабли.

***

В итоге, в данном конкретном случае я купился. Перспектива нарисовать мышкой модель данных и автоматом заиметь ее персистентность в RDBMS и экспозабилити по HTTP очень соблазняет, даже несмотря на то, что где-то тут будут грабли. Не останавливает даже и врожденное стремание перед вещами, которые нельзя дописать под себя в случае чего. Что ж, поживем - увидим.