Tuesday 1 April 2014

GeoREST as re-imagined by mapguide-rest: Part 1

So after a little tour of the REST API, we now come to the other half of mapguide-rest: The re-imagined GeoREST-style data publishing framework.

If you have used GeoREST before, most of what I will be showing here should be familiar to you conceptually.

Introduction

If you've never used GeoREST before, it is a framework for publishing spatial data (from a MapGuide Feature Source or a raw FDO connection) in one or more various formats and representations, such as:
  • GeoJSON
  • XML
  • OData
  • PNG
  • HTML (via templates)
  • KML (via templates)
  • GeoRSS (via templates)
  • CSV (via templates)
Published spatial data sources follow RESTful principles for interaction and data access.
  • Clients use HTTP GET to "read" features from the data source
  • Clients use HTTP POST to "create" features in the data source
  • Clients use HTTP PUT to "update" features in the data source
  • Clients use HTTP DELETE to "delete" features in the data source
GeoREST enables CRUD for certain Feature Sources without needing to know specifics of the MapGuide API. Accessing this data does not require the use any specialized client libraries and APIs or knowledge of SOAP or other specialized RPC mechanisms. Only knowledge of how to make HTTP requests is required. Based on the type of representation and what's configured for the data source, certain operations may or may not be supported.

The other major feature is that access to such data will generally have clean URLs which assists in bookmark-ability and makes such published data easy to access by humans and machines alike.

While GeoREST offers something unique, for mapguide-rest I wanted to go back to the drawing board on this idea for reasons already stated.

Differences from GeoREST

The main differences in mapguide-rest that distinguish it from GeoREST are:
  • Configuration is done by JSON files instead of XML files
  • Because mapguide-rest is in PHP, it also works in Linux versions of MapGuide/AIMS where GeoREST is windows-only.
  • mapguide-rest is not tied to a specific version of MapGuide/AIMS and can work on any version of MapGuide/AIMS that bundles PHP 5.3 or newer (though we recommend using it on the latest releases).
  • Also because of PHP, mapguide-rest uses the more powerful and flexible Smarty template engine for any template-based representations instead of GeoREST's ctemplate engine allowing for more expressive content templates.
  • The base URL where data sources in mapguide-rest can be accessed is strictly based on the relative location of its configuration file and not based on the value of uripart in restcfg.xml for GeoREST.
  • mapguide-rest provides an easy API to extend it with your own custom formats/representations or geometry/datetime formatters for templated content.
  • mapguide-rest provides coordinate transformation capabilities out of the box.
  • mapguide-rest in its current iteration is yet to support OData like GeoREST currently does.
  • mapguide-rest does not support raw FDO connections as a data source. Only MapGuide Feature Sources are supported.
Configuration

Configuration files are JSON-based and reside under the /conf/data subdirectory of your mapguide-rest installation. These files can reside any levels deep within this folder. These configuration files are named restcfg.json and its relative location determines the base URL in which to access that particular configured data source.

Here's a basic example restcfg.json

{
    "Source": {
        "Type": "MapGuide",
        "FeatureSource": "Library://Samples/Sheboygan/Data/Parcels.FeatureSource",
        "FeatureClass": "SHP_Schema:Parcels"
    },
    "Representations": {
        "xml": {
            "Adapter": "FeatureSetXml",
            "Methods": {
                "GET": {
                    "PageSize": 100,
                    "MaxCount": 500
                }
            }
        },
        "html": {
            "Adapter": "Template",
            "Methods": {
                "GET": {
                    "PageSize": 100,
                    "MaxCount": 500,
                    "MimeType": "text/html",
                    "Templates": {
                        "Single": "property_html_single.tpl",
                        "Many": "property_html_many.tpl",
                        "None": "property_html_none.tpl",
                        "Error": "property_html_error.tpl"
                    }
                }
            }
        }
    }
}

As you can see, the structure of restcfg.json is easy to follow:
  • There is a top-level Source property that indicates the MapGuide Feature Source that we want to make available for RESTful access
  • There is a top-level Representations property that contains one or more supported data formats that specifies the Adapter that will handle this particular representation along with adapter-specific configuration options for each HTTP method that you want to allow through that particular representation (and is supported by the given adapter)
The above restcfg.json enables the Parcels Feature Source to be accessible:
  • As XML data
  • As a set of web pages with master-detail type of navigation
URL Conventions

All URLs follow the following forms:
  • Multiple results: http://servername/mapguide/rest/data/[RELATIVEURIPART]/.[FORMAT]
  • Single results: http://servername/mapguide/rest/data/[RELATIVEURIPART]/[FEATUREID].[FORMAT]
As mentioned above, the location of restcfg.json will determine the base URL which to access data from this particular data source. The RELATIVEURIPART of the above URLs is based on the relative path of this restcfg.json file.

For example, if restcfg.json was stored like so

 - REST_INSTALL_DIR
    - conf
       - data
          - sheboygan
             - property
                - restcfg.json

Then the URL for accessing the detail page of a specific parcel would be:

http://servername/mapguide/rest/data/sheboygan/property/1.html

The FORMAT of the above URL is the name of the extension keyed under the Representations part of restcfg.json and will let mapguide-rest determine which adapter to instantiate to handle this particular request.

For individual feature access, specifying the value of [FEATUREID] will cause the designated adapter to only return the matching feature whose identity property value is [FEATUREID] in the adapter's given format/representation.

All adapters will be processing URLs in these two forms.

Adapters

Adapters are classes in mapguide-rest which will be instantiated based on the given extension in the incoming URL and will be used to handle the particular HTTP request. Adapters will perform specific actions based on the request URL and the particular HTTP method used.

For example, for the FeatureSetXml adapter:

  • A HTTP GET will return one or more features from the Feature Source in XML format
  • A HTTP POST will insert one or more features into the given Feature Source based on the XML content in the request body
  • A HTTP PUT will update one or more features in the given Feature Source based on the filter and properties specified in the XML request body
  • A HTTP DELETE will delete one or more features in the given Feature Source based on the filter specified in the request parameters
Other adapters may only support certain methods (for the record, only FeatureSetXml supports GET/POST/PUT/DELETE. Other adapters only support GET)

mapguide-rest includes the following adapters:
  • FeatureSetXml - Outputs feature data as XML, also supports create/update/delete of features if configured
  • FeatureSetJson - Outputs feature data as GeoJSON
  • FeatureSetCsv - Outputs feature data as a CSV file. Geometry values are written as WKT
  • MapImage - Outputs feature data as a map image with the feature(s) in question being selected
  • Template - Outputs feature data through a user-defined smarty template.
Adapters are the key to how data publishing works in mapguide-rest. I have a feeling that this could be a somewhat lengthy series of posts. So I'll stop here for now. Stay tuned as I go through each adapter in greater detail.

No comments: