Создание простейшего HTTP-сервиса для публикации векторных данных
Введение
При разработки Веб-ГИС зачастую возникает необходимость в передаче векторных данных с сервера на клиентскую сторону. При этом, как правило, векторные данные имеют большой объем или находятся в различных хранилищах и поэтому вариант передачи данных в виде одного файла сразу же исключается. Очевидно, что требуется некоторое промежуточное звено, которое бы могло получать от клиентского приложения запрос данных, удовлетворяющих определенному критерию (например, попадающие в некий охват), подключаться к хранилищу данных, извлекать нужный набор и возвращать его клиенту.
Для решения данной задачи существует специальный протокол OGC Web Feature Service, о котором мы рассказывали в одной из предыдущих статей. С одной стороны, опубликовав свои данные по WFS, мы получаем очень богатые возможности:
- отображение данных в настольных ГИС;
- гибкий язык описания фильтров;
- возможность редактирования данных.
Если бы перед нами стояла задача просто опубликовать некоторый набор данных по WFS, то никаких проблем - берем TinyOWS, MapServer или GeoServer, настраиваем подключение к хранилищу - всё. Но это не наш случай, нам нужно добавить WFS-функционал непосредственно в наше приложение. Как поступить в этом случае? Вариантов на самом деле не много: либо найти необходимую библиотеку на том языке программирования, на котором ведется разработка, либо каким-то образом "прикрутить" имеющийся WFS-сервер к нашему приложению. Не беремся утверждать за другие языки программирования, но, например, в случае Python не существует нативных библиотек, реализующих функционал WFS-сервиса, только лишь баиндинги к mapscript, а это по сути сводится к установке библиотек MapServer (который написан на C/C++). Завязывание же своего приложения на внешний по отношению к нему WFS-сервер - задача непростая и вызывающая ряд очень серьезных проблем:
- необходимость подготовки дистрибутива WFS-сервера под целевую платформу;
- язык программирования, используемый при разработке основного приложения и WFS-сервера зачастую не совпадают, следовательно в случае возникновение проблем с последним, необходимо привлечение дополнительных ресурсов;
- сама задача по интеграции приложение с WFS-сервером далеко не тривиальная.
Поэтому, если вы все-таки хотите использовать возможности WFS в своем приложении, то наиболее правильным видится подход в разработке соответствующего ПО на том же языке программирования, что используется в вашем приложении. В этом случае вы имеете полный контроль над своей системой.
Как показывает практика, для разработки небольших картографических Веб-приложений функционал, предлагаемый спецификацией WFS, крайне избыточен. Зачастую нам не нужно ни отображать наши данные в настольных ГИС, ни иметь гибкий язык описания фильтров, поэтому в большинстве случаев достаточно написания собственного простейшего HTTP-сервиса, возвращающего данные в каком-нибудь стандартном формате (например,GeoJSON). Именно решению данной задачи и будет посвящена оставшаяся часть статьи. В качестве примера использования подобного сервиса может служить проект Найди участкового, откройте консоль вашего браузера и посмотрите какие запросы уходят на сервер при сдвиге карты.
В качестве языка программирования будем использовать Python, операционная система - Debian GNU/Linux 7.0.
Выбор API
Если вам требуется разработать полнофункциональный HTTP-сервис, то чтобы не изобретать велосипед, можно взять готовое описание какого-нибудь API (в зависимости от задач) и реализовать его, например, MapFish Protocol или ArcGIS Server REST API (открытая реализация HTTP-сервиса, реализующая данный API уже существует).
В нашем случае мы разработаем HTTP-сервис, поддерживающий 3 GET-параметра:
- bbox={xmin,ymin,xmax,ymax} - запрашиваемый bbox (по умолчанию считается, что координаты указаны в системе координат EPSG:4326);
- epsg={num} - система координат в которой должны быть возвращены данные, также используется как система координат для bbox;
- attrs={field1}[,{field2},...] - имена запрашиваемых атрибутивных полей.
Хранилище и формат выходных данных
В качестве данных возьмем БД PostGIS, созданную в рамках проекта по созданию слоя детских учреждений. Выходной формат - GeoJSON.
При разработке Веб-ГИС стандартная практика заключается в передаче данных клиенту в формате GeoJSON, при этом объект GeoJSON - это объект типа "FeatureCollection" - коллекция элементарных объектов. Объект типа "FeatureCollection" содержит одно свойство "features", значение данного свойства – массив, каждый элемент которого представляет собой элементарный объект.
В PostgreSQL, начиная с версии 9.2, появились специальные функции для работы с JSON-данными, в частности row_to_json, позволяющие, используя SQL-запрос к базе данных PostGIS, получить "FeatureCollection". О том как это сделать подробно описано в статье Creating GeoJSON Feature Collections with JSON and PostGIS functions, мы же ввиду того что используемое нами хранилище развернуто на PostgreSQL 9.1 будем формировать "FeatureCollection" самостоятельно в коде нашего сервиса.
Веб-фреймворк
Для того, чтобы облегчить себе жизнь и не писать служебный код в качестве инструмента для работы с HTTP-запросами выберем какой-нибудь Веб-фреймворк. Остановимся на Bottle. Данный фреймворк уже использовался нами в статье Основы работы динамических TMS-сервисов.