- Preparando o ambiente de teste =================================
Para testar a API REST do GeoServer utilizaremos Python aliado ao módulo requests. Baixe os seguintes pacotes:
- Python 2.7 (ou superior) em python.org.
- cURL (para testes rápidos via terminal) em curl.haxx.se. Use a versão
curl-7.53.1-win64-mingw. - Biblioteca
requestsdo Python: github.com/kennethreitz/requests.
Após instalar o Python, configure as variáveis de ambiente. No diretório onde o requests foi baixado, execute:
python setup.py install
Verifique a instalação:
~$ python
>>> import requests
- Obtendo lista de workspaces com cURL =======================================
Extraia o cURL e entre na pasta curl-7.53.1-win64-mingw\bin. Execute:
curl -u admin:geoserver -v -XGET -H 'Accept: text/xml' http://localhost:8082/geoserver/rest/workspaces -o workspace.xml
Parâmetros: -u autenticação, -v verbose, -X método HTTP, -H cabeçalho, -o salva resposta em arquivo.
- Obtendo workspaces com Python ================================
Em um diretório de saída, execute passo a passo no Python:
python
>>> import requests
>>> url = 'http://localhost:8082/geoserver/rest/workspaces'
>>> cabecalhos = {'Accept': 'text/xml'}
>>> resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
>>> resposta.status_code
>>> arquivo = open('workspaces_py.xml','w')
>>> arquivo.write(resposta.text)
>>> arquivo.close()
O conteúdo gerado é idêntico ao do cURL.
- Listando datastores de um workspace ======================================
Altere a URL para o workspace desejado (ex.: tiger):
url = 'http://localhost:8082/geoserver/rest/workspaces/tiger'
A resposta inclui links para datastores, coverageStores e wmsStores.
- Navegando por namespaces ===========================
Listar todos os namespaces:
url = 'http://localhost:8082/geoserver/rest/namespaces'
Consultar um namespace específico:
url = 'http://localhost:8082/geoserver/rest/namespaces/tiger'
- Criando um namespace =======================
Com cURL:
curl -u admin:geoserver -XPOST -H 'Content-type: text/xml' -d '<namespace><prefix>novoWorkspace</prefix><uri>http://geoserver.org</uri></namespace>' http://localhost:8082/geoserver/rest/namespaces
Com Python:
url = 'http://localhost:8082/geoserver/rest/namespaces'
arquivo = open('corpo.xml','r')
payload = arquivo.read()
cabecalhos = {'Content-type': 'text/xml'}
resposta = requests.post(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
print(resposta.status_code)
Conteúdo do arquivo corpo.xml:
<namespace><prefix>novoWorkspace</prefix><uri>http://geoserver.org</uri></namespace>
- Alterando um namespace =========================
url = 'http://localhost:8082/geoserver/rest/namespaces/novoWorkspace'
arquivo = open('corpo.xml','r')
payload = arquivo.read()
cabecalhos = {'Content-type': 'text/xml'}
resposta = requests.put(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
Arquivo corpo.xml atualizado:
<namespace><prefix>novoWorkspace</prefix><uri>http://localhost:8082/geoserver</uri></namespace>
- Excluindo um namespace =========================
url = 'http://localhost:8082/geoserver/rest/workspaces/novoWorkspace'
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.delete(url, auth=('admin','geoserver'), headers=cabecalhos)
print(resposta.status_code)
- Listando datastores de um workspace ======================================
url = 'http://localhost:8082/geoserver/rest/workspaces/tiger/datastores'
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('tiger_datastores.xml','w')
arquivo.write(resposta.text)
arquivo.close()
Saída:
<dataStores>
<dataStore>
<name>50m-rivers-lake-centerlines</name>
<atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="alternate" href="http://localhost:8082/geoserver/rest/workspaces/tiger/datastores/50m-rivers-lake-centerlines.xml" type="application/xml"/>
</dataStore>
<dataStore>
<name>ne_10m_railroads</name>
...
</dataStore>
</dataStores>
- Detalhes de um datastore específico =======================================
url = 'http://localhost:8082/geoserver/rest/workspaces/tiger/datastores/ne_50m_populated_places'
cabecalhos = {'Accept': 'text/html'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('tiger_datastore_detalhe.html','w')
arquivo.write(resposta.text)
arquivo.close()
Retorna uma página HTML com o nome do datastore e links para as feature types.
- Criando um novo datastore =============================
url = 'http://localhost:8082/geoserver/rest/workspaces/tiger/datastores'
arquivo = open('tigerCounties.xml','r')
payload = arquivo.read()
cabecalhos = {'Content-type': 'text/xml','Accept': 'text/xml'}
resposta = requests.post(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
print(resposta.status_code)
Conteúdo de tigerCounties.xml:
<dataStore>
<name>tl_2011_47_concity_REST</name>
<description>condados tiger criados via REST</description>
<type>Shapefile</type>
<enabled>true</enabled>
<connectionParameters>
<entry key="memory mapped buffer">false</entry>
<entry key="create spatial index">true</entry>
<entry key="charset">ISO-8859-1</entry>
<entry key="filetype">shapefile</entry>
<entry key="cache and reuse memory maps">true</entry>
<entry key="url">C:\dados\tl_2011_47_concity\tl_2011_47_concity.shp</entry>
<entry key="namespace">http://www.census.gov</entry>
</connectionParameters>
<__default>false</__default>
</dataStore>
- Alterando um datastore ==========================
Similar à criação, mas usando método PUT:
resposta = requests.put(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
- Excluindo um datastore ==========================
url = 'http://localhost:8082/geoserver/rest/workspaces/tiger/datastores/tl_2011_47_concity_REST'
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.delete(url, auth=('admin','geoserver'), headers=cabecalhos)
- Upload de shapefile via PUT ===============================
Envia um arquivo ZIP contendo o shapefile:
url = 'http://localhost:8082/geoserver/rest/workspaces/tiger/datastores/Meu+Shape+Novo/file.shp'
arquivo = open('110m-admin-0-countries.zip','rb')
payload = arquivo.read()
cabecalhos = {'Content-type': 'application/zip'}
resposta = requests.put(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
O nome Meu+Shape+Novo é o nome do datastore, e file.shp é o nome interno do shape no servidor. O ZIP é extraído automaticamente.
- Adicionando uma tabela do PostGIS como camada =================================================
Considere um datastore PostGIS já existente (myPostGIS no workspace cite). Para mapear a tabela ne_110m_admin:
url = 'http://localhost:8082/geoserver/rest/workspaces/cite/datastores/myPostGIS/featuretypes'
payload = '<featureType><name>ne_110m_admin</name></featureType>'
cabecalhos = {'Content-type': 'text/xml'}
resposta = requests.post(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
Para configuração mais rica (título, palavras‑chave, SRS, atributos):
<featureType>
<name>Fronteiras Mundiais</name>
<nativeName>ne_110m_admin</nativeName>
<title>Fronteiras Mundiais</title>
<abstract>Limites administrativos mundiais em pequena escala</abstract>
<keywords>
<string>Político</string>
<string>Mundo</string>
</keywords>
<srs>EPSG:4326</srs>
<attributes>
<attribute>
<name>geom</name>
<binding>com.vividsolutions.jts.geom.MultiPolygon</binding>
</attribute>
<attribute>
<name>nome</name>
<binding>java.lang.String</binding>
<length>50</length>
</attribute>
</attributes>
</featureType>
- Consultando estilos =======================
url = 'http://localhost:8082/geoserver/rest/styles/PopulatedPlacesLabeled'
cabecalhos = {'Accept': 'application/vnd.ogc.sld+xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('estilo.xml','w')
arquivo.write(resposta.text)
arquivo.close()
- Criando um novo estilo ==========================
url = 'http://localhost:8082/geoserver/rest/styles'
arquivo = open('novo_estilo.xml','r')
payload = arquivo.read()
cabecalhos = {'Content-type': 'application/vnd.ogc.sld+xml'}
resposta = requests.post(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
- Documentação completa da API REST =====================================
Consulte a documentação oficial.
- Capacidades do serviço WFS ==============================
url = 'http://localhost:8082/geoserver/wfs?service=wfs&version=1.0.0&request=GetCapabilities'
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('capabilities_wfs.xml','w')
arquivo.write(resposta.text)
arquivo.close()
O arquivo contém todos os FeatureTypes com name, title, SRS e bounding box.
- Descrição detalhada de um FeatureType =========================================
url = "http://localhost:8082/geoserver/wfs?service=wfs&version=1.0.0&request=DescribeFeatureType&TypeName=tiger:tiger_roads"
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('describe_tiger_roads.xml','w')
arquivo.write(resposta.text)
arquivo.close()
Retorna o esquema XSD com os atributos e tipos.
- Recuperando dados de um FeatureType =======================================
url = "http://localhost:8082/geoserver/wfs?service=wfs&version=1.1.0&request=GetFeature&TypeName=tiger:tiger_roads&maxFeatures=1"
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('feature_tiger_roads.xml','w')
arquivo.write(resposta.text)
arquivo.close()
Filtrando por bounding box:
url = "http://localhost:8082/geoserver/wfs?service=wfs&version=1.0.0&request=GetFeature&TypeName=tiger_roads&bbox=-116.68,36.29,-111.36,39.90"
Exemplo de resposta (pseudocódigo):
<wfs:FeatureCollection ...>
<gml:boundedBy><gml:null>unknown</gml:null></gml:boundedBy>
<gml:featureMember>
<NaturalEarth:10m_railroads fid="10m_railroads.481">
<NaturalEarth:the_geom>
<gml:MultiLineString srsName="..."/>
</NaturalEarth:the_geom>
<NaturalEarth:ScaleRank>8</NaturalEarth:ScaleRank>
<NaturalEarth:FeatureCla>Railroad</NaturalEarth:FeatureCla>
...
</NaturalEarth:10m_railroads>
</gml:featureMember>
</wfs:FeatureCollection>
- Capacidades do serviço WCS ==============================
url = "http://localhost:8082/geoserver/wcs?service=wcs&version=1.0.0&request=GetCapabilities"
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('capabilities_wcs.xml','w')
arquivo.write(resposta.text)
arquivo.close()
Retorna metadados de cada cobertura, como:
<wcs:CoverageOfferingBrief>
<wcs:name>nurc:Img_Sample</wcs:name>
<wcs:label>Amostra de imagens da América do Norte</wcs:label>
...
</wcs:CoverageOfferingBrief>
- Descrição detalhada de uma cobertura ========================================
url = "http://localhost:8082/geoserver/wcs?service=wcs&version=1.0.0&request=DescribeCoverage&Coverage=nurc:Img_Sample"
cabecalhos = {'Accept': 'text/xml'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('descricao_cobertura.xml','w')
arquivo.write(resposta.text)
arquivo.close()
- Baixando dados de uma cobertura ===================================
url = "http://localhost:8082/geoserver/wcs?service=wcs&version=1.0.0&request=GetCoverage&coverage=nurc:Img_Sample&crs=EPSG:4326&bbox=-130.85168,20.7052,-62.0054,54.1141&width=982&height=597&format=geotiff&bands=1"
cabecalhos = {'Accept': 'image/tiff'}
resposta = requests.get(url, auth=('admin','geoserver'), headers=cabecalhos)
arquivo = open('cobertura.tiff','wb')
arquivo.write(resposta.content)
arquivo.close()
O resultado é um arquivo GeoTIFF com a imagem solicitada.