Usando a API REST do GeoServer

  1. Preparando o ambiente de teste =================================

Para testar a API REST do GeoServer utilizaremos Python aliado ao módulo requests. Baixe os seguintes pacotes:

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
  1. 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.

  1. 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.

  1. 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.

  1. 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'
  1. 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>
  1. 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>
  1. 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)
  1. 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>
  1. 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.

  1. 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>
  1. Alterando um datastore ==========================

Similar à criação, mas usando método PUT:

resposta = requests.put(url, auth=('admin','geoserver'), data=payload, headers=cabecalhos)
  1. 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)
  1. 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.

  1. 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>
  1. 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()
  1. 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)
  1. Documentação completa da API REST =====================================

Consulte a documentação oficial.

  1. 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.

  1. 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.

  1. 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>
  1. 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>
  1. 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()
  1. 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.

Tags: GeoServer REST API Python cURL

Publicado em 7-15 03:57