- 如何用PostgREST、PostgreSQL和PostGIS构建强大的空间restapi?
以往我们在使用PostGIS做空间分析或者需要前端进行WFS或者空间分析的时候,可能会使用GeoServer发布图层,或者用Geotools自定义,但是使用
如何用PostgREST就不需要了,我们一起看看如何实现吧。
在本教程中,你将学习如何使用强大的PostgREST库在其引擎盖下构建一个SpatialRESTAPI—只需几分钟!
我们将使用以下功能实现一系列不同的API:
如果您以前从未听说过PostgREST,那么让我们看看作者是怎么说的:
PostgREST是一个独立的web服务器,它将PostgreSQL数据库直接转换为restfulapi。数据库中的结构约束和权限决定了API端点和操作。
再简单不过了。
要实现本教程的所有步骤,需要安装PostgreSQL、PostGIS和PostgREST。您可以使用我们的安装教程,它将帮助您建立并运行一个docker容器,PostgREST将在随后的步骤中使用它。
安装和设置PostgreSQL、PostGIS和PostgREST本文不详细讨论,详见如下地址或者本公众号的专题文章:
https://github.com/gis-ops/tutorials/blob/postgrest-elevation-api/postgres/postgres_postgis_postgrest_installation.md
步骤1-让我们返回一个简单的GeoJSON对象
如前所述,我们将实现动态计算空间信息的存储过程。作为用户,您将能够将GeoJSON对象作为有效负载发布到API。为了演示,我们将从一个简单的过程开始,它将返回有效载荷而不更改它。
让我们回到psql提示符:
sudo docker exec -it postgrest_tut psql -U postgres
我们将在api模式中添加一个简单的函数。它接受一个JSON参数,然后按原样返回它。
CREATE OR REPLACE FUNCTION api.singlegeojsonparam(single_param json) RETURNS json
LANGUAGE sql
AS $_$
SELECT single_param;
$_$;
按回车键。。。就这样,我们来试试吧!
curl -X POST \
http://localhost:3000/rpc/singlegeojsonparam \
-H 'Content-Type: application/json' \
-H 'Prefer: params=single-object' \
-d '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[100.0,0.0],[101.0,0.0],[101.0,1.0],[100.0,1.0],[100.0,0.0]]]},"properties":{"prop0":"value1","prop1":{"this":"that"}}},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[100.0,0.0],[101.0,0.0],[101.0,1.0],[100.0,1.0],[100.0,0.0]]]},"properties":{"prop0":"value2","prop1":{"this":"that"}}}]}'
如果你对发送JSON数据的POST请求不太熟悉,这可能对您来说有点陌生。body只是一个JSON对象,通常它的键会被解释为body参数。但是,通过指定请求头Prefer:params=single object,我们可以让后端知道将整个POST主体解释为单个参数的值。对于只需要一个JSON对象的端点来说非常方便。
步骤2-计算字符串的长度
现在我们可以从一些有趣的事情开始。让我们继续编写一个函数,该函数能够计算wgs84也就是EPSG4326。注意,我们提供的GeoJSON是以度为单位的,因此我们必须转换为pseudo-mercator(或类似的东西)。另外,我们将把它转换成数字,然后除以1.000(以公里为单位得到结果),我们将它四舍五入到2位小数。
CREATE OR REPLACE FUNCTION api.calc_length(linestring json) RETURNS numeric AS $$
SELECT ROUND(
CAST(
ST_Length(
ST_Transform(
ST_GeomFromGeoJSON(LineString), 54030
)
)/1000 AS numeric
),2
)
$$ LANGUAGE SQL;
很简单。让我们试试看。
curl -X POST \
http://localhost:3000/rpc/calc_length \
-H 'Content-Type: application/json' \
-H 'Prefer: params=single-object' \
-d '{"type":"LineString","coordinates":[[-101.744384,39.32155],[-101.552124,39.330048],[-101.403808,39.330048],[-101.332397,39.364032],[-101.041259,39.368279],[-100.975341,39.304549],[-100.914916,39.245016],[-100.843505,39.164141],[-100.805053,39.104488],[-100.491943,39.100226],[-100.437011,39.095962],[-100.338134,39.095962],[-100.195312,39.027718],[-100.008544,39.010647],[-99.865722,39.00211],[-99.684448,38.972221],[-99.51416,38.929502],[-99.382324,38.920955],[-99.321899,38.895308],[-99.113159,38.869651],[-99.0802,38.85682],[-98.822021,38.85682],[-98.448486,38.848264],[-98.206787,38.848264],[-98.020019,38.878204],[-97.635498,38.873928]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}'
喂!返回美国堪萨斯州的边界数据是:
367.15
单位是公里!
步骤3-计算多边形的面积
到目前为止,您很可能已经掌握了实现定制函数是多么容易的要点。类似于线串的例子,我们也可以计算多边形的面积。让我们让这变得更加棘手,让用户发送一个GeoJSON FeatureCollection。为了简单一点,端点只能处理FeatureCollection的第一个特征,因此只能处理一个多边形。
CREATE OR REPLACE FUNCTION api.calc_area(featurecollection json) RETURNS numeric AS $$
SELECT ROUND(
CAST(
ST_Area(
ST_Transform(
ST_GeomFromGeoJSON(
featurecollection->'features'->0->'geometry'
), 54030
)
)/1000000 AS numeric
),2
)
$$ LANGUAGE SQL;
让我们看看结果:
curl -X POST \
http://localhost:3000/rpc/calc_area \
-H 'Content-Type: application/json' \
-H 'Prefer: params=single-object' \
-d '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-73.6962890625,41.02135510866602],[-73.8446044921875,41.253032440653186],[-74.168701171875,41.20758898181025],[-74.44335937499999,40.88444793903562],[-74.520263671875,40.60144147645398],[-74.2840576171875,40.53050177574321],[-73.8885498046875,40.63479884404164],[-72.83935546875,40.805493843894155],[-72.6800537109375,40.950862628132775],[-73.6962890625,41.02135510866602]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}}]}'
我们的多边形覆盖了纽约的一部分
6017.49
单位是平方公里。
步骤4-计算2个多边形的交集
最后,让我们再实现一个函数来计算两个多边形的交集。现在的功能应该是不言而喻的。我们只需要确保返回的是GeoJSON而不是数值。
CREATE OR REPLACE FUNCTION api.calc_intersection(featurecollection json) RETURNS json AS $$
SELECT ST_AsGeoJSON(
ST_Intersection(
ST_GeomFromGeoJSON(
featurecollection->'features'->0->'geometry'
),
ST_GeomFromGeoJSON(
featurecollection->'features'->1->'geometry'
)
)
)::json;
$$ LANGUAGE SQL;
我们将用一个包含2个多边形的特性集合来调用这个API。
curl -X POST \
http://localhost:3000/rpc/calc_intersection \
-H 'Content-Type: application/json' \
-H 'Prefer: params=single-object' \
-d '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-73.6962890625,41.02135510866602],[-73.8446044921875,41.253032440653186],[-74.168701171875,41.20758898181025],[-74.44335937499999,40.88444793903562],[-74.520263671875,40.60144147645398],[-74.2840576171875,40.53050177574321],[-73.8885498046875,40.63479884404164],[-72.83935546875,40.805493843894155],[-72.6800537109375,40.950862628132775],[-73.6962890625,41.02135510866602]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-73.6798095703125,41.56203190200195],[-74.3280029296875,41.75492216766298],[-74.34997558593749,41.74262728637672],[-74.7894287109375,41.21998578493921],[-74.29504394531249,40.87614141141369],[-73.4326171875,40.91766362458114],[-73.6798095703125,41.56203190200195]]],"crs":{"type":"name","properties":{"name":"EPSG:4326"}}}}]}'
它将以GeoJSON交集响应。
{
"type": "Polygon",
"coordinates": [
[
[
-74.3926939034368,
40.944056911669
],
[
-74.168701171875,
41.2075889818102
],
...
]
]
}
总结
恭喜您完成本教程。现在,您将了解如何使用PostGIS设置和使用PostgREST web API进行空间分析和查询。
与其他框架相比,它可能是我们遇到过的最直接的web框架。这显然只触及了可能的表面,但是如果您正在寻找一种快速的方法来设置API来动态处理空间计算,我们绝对可以推荐使用PostgREST。