Sunday, 16 February 2014

Cool things to do with the mapguide-rest API: Part 2

Now for part 2 of the cool things you can do with the mapguide-rest API.

Making a new MgMap

mapguide-rest provides a shim to the CREATERUNTIMEMAP operation that returns the same response as the operation we've introduced for the MapGuide 2.6 release. Except this one can work with older releases as well.

POST http://servername/mapguide/rest/services/createmap.xml
mapdefinition = Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition
requestedfeatures = 7

Or if you want a JSON version

POST http://servername/mapguide/rest/services/createmap.json
mapdefinition = Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition
requestedfeatures = 7

Creating a map with the above operation will also create a selection set as well with the same map name (which you can find out inside the response of the above operation)

MgMap interaction

Having created a Runtime Map, here's how you can describe and interact with it.

In case you created a Runtime Map without requesting a layer structure, you can request it like so:

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/layers.xml

Or if you want a JSON version

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/layers.json

You can list the groups in the same fashion

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/layergroups.xml

Or if you want a JSON version

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/layergroups.json

But the most important thing you want to do with a runtime map is to render an image of it, here's how you do it

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/overlayimage.png?x=-87.73&y=43.74&scale=75000&width=800&height=600&behavior=2

Note that like GETDYNAMICMAPOVERLAYIMAGE, setting X/Y/Scale/DPI/width/height modifies the state of the MgMap. Knowing some math, you have the means of building a basic map viewer by tweaking the x, y and scale parameters based on mouse clicks and movements.

If you want to request a non-overlay image (ie. GETMAPIMAGE instead of GETDYNAMICMAPOVERLAYIMAGE), just replace overlayimage.png with image.png

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/image.png?x=-87.73&y=43.74&scale=75000&width=800&height=600

You can also request a DWF plot of this map in its current view as well

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/plot.dwf

Or if you have a PrintLayout, you can request a DWF plot using the specified layout.

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Map/plot.dwf?printlayout=Library://Samples/Sheboygan/Layouts/SheboyganMap.PrintLayout

Map Selection interaction

Like the Runtime Map, there are many ways to interact with a map selection. Like the Runtime Map, interaction with a map selection requires a session id and the map name.

Here's how you get the raw XML of the selection

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/xml

Here's how you can describe what layers are in the selection set

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/layers.xml

Or if you want a JSON version

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/layers.json

If you want to get the actual selected features

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/features.xml/Parcels

Or if you want a more usable format like GeoJSON

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/features.geojson/Parcels

And with any request that returns feature data, we support transform-ability out of the box

GET http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/features.geojson/Parcels?transformto=WGS84.PseudoMercator

There are 2 ways to manipulate selections.

First is by using the shim to QUERYMAPFEATURES

PUT http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection
geometry = POLYGON((-87.72464513939002 43.756626600485,-87.72464513939002 43.757316392651,-87.723570655439 43.757316392651,-87.723570655439 43.756626600485,-87.72464513939002 43.756626600485))
selectionvariant = INTERSECTS
requestdata = 15
selectioncolor = 0xFF000000
selectionformat = PNG
maxfeatures = -1
persist = 1

format = json

The other way is to POST the selection XML 

POST http://servername/mapguide/rest/session/my-mapguide-session-id/my-map-name.Selection/xml

OpenLayers support

If you want to see more concrete examples of map and selection interaction, you can check out the OpenLayers samples included with mapguide-rest, which have been ported over from the ones that will be included in MapGuide Open Source 2.6. These sample use a new OpenLayers.Layer.MapGuideREST class which uses the REST APIs offered by mapguide-rest.

Next post will focus on the other half of mapguide-rest, the data publishing replacement for GeoREST

Monday, 10 February 2014

Cool things to do with the mapguide-rest API: Part 1

Rather than give a verbatim overview of everything that is provided by the REST API in mapguide-rest (because a blog post that is just raw API documentation doesn't exactly sound like thrilling content to read), I'm going to approach this from a different angle.

For this series of posts, I'm going to specifically focus on some of the cool things you can do through the REST API that is either:

  1. Not possible through the mapagent
  2. Is possible through the mapagent, but is really unintuitive or returns content in an undesirable format
For anything else, I'd figure you could either just figure it out from the URLs provided by the various HTML representations available:
  • Site Repository: http://servername/mapguide/rest/library/list.html
  • Coordinate System Catalog: http://servername/mapguide/rest/coordsys/categories.html
  • FDO Provider Registry: http://servername/mapguide/rest/providers.html

Querying Features

Querying data from Feature Sources is possible using the SELECTFEATURES operation in the mapagent, but has some issues that make it difficult for client applications to use:
  • The operation is very verbose and requires lots of parameters to set up.
  • The operation returns MapGuide-specific XML data, and its JSON response is a direct 1:1 conversion of the XML format.
Querying data from Feature Sources through our REST API on the other hand is a simple and intuitive affair. This is because most of the base information is in the URL itself with optional parameters specified in the query string. For example, returning all data from the feature source Library://Samples/Sheboygan/Data/Parcels.FeatureSource is simply issuing the following GET request:

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/features.xml/SHP_Schema/Parcels

This will return everything from the Parcels Feature Source under the SHP_Schema:Parcels feature class in XML format.

From this basic request, you can apply all sorts of extra parameters in various permutations to shape the response to your liking

Want to filter the data? Pass a filter parameter with your URL-encoded FDO filter string

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/features.xml/SHP_Schema/Parcels?filter=RNAME%20LIKE%20'SCHMITT%25'

Where (RNAME%20LIKE%20'SCHMITT%25') is the URL-encoded form of (RNAME LIKE 'SCHMITT%')

Want to filter the same data by bounding box instead? Pass a bbox parameter with an x1,y1,x2,y2 quartet.

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/features.xml/SHP_Schema/Parcels?bbox=-87.6,43.7,-87.7,43.8

Want to cap the results to 500 features maximum? Pass a maxfeatures parameter

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/features.xml/SHP_Schema/Parcels?maxfeatures=500

Want the geometry data transformed to a different coordinate system (eg. Web Mercator)? Pass a transformto parameter

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/features.xml/SHP_Schema/Parcels?transformto=WGS84.PseudoMercator

And here's possibly the best one of the lot, want the data in a more usable format than XML like GeoJSON? Sure you can!

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/features.geojson/SHP_Schema/Parcels

Aggregating data

Unlike the feature querying capabilities, the aggregation capabilities of the REST API are much more simplified and is focused around 3 key common scenarios:
  • Counting the number of features
  • Getting the bounding box of a feature class
  • Getting the distinct list of values for a given property
So using the same Parcels feature source, here's how you can count the number of features

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/aggregates.xml/count/SHP_Schema/Parcels

Here's how you get a bounding box

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/aggregates.xml/bbox/SHP_Schema/Parcels

Want it in a different coordinate system? Pass a transformto parameter.

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/aggregates.xml/bbox/SHP_Schema/Parcels?transformto=WGS84.PseudoMercator

Here's how you can get a distinct set of RTYPE property values

GET http://servername/mapguide/rest/library/Samples/Sheboygan/Data/Parcels.FeatureSource/aggregates.xml/distinctvalues/SHP_Schema/Parcels?property=RTYPE

And finally, if you want this in JSON instead of XML, just use aggregates.json in the URL instead of aggregates.xml

Transforming Coordinates

Here's something you definitely can't do through the mapagent. 

With the rise of HTML5 and powerful client-side web applications, probably the greatest irony about MapGuide as a web mapping solution is that we have one of the most powerful Coordinate System libraries with comprehensive support for every coordinate system on this planet you could imagine but ... we can't even tap into this library on the client-side in the web browser where it probably matters the most! It's why Fusion, OpenLayers, etc use libraries like Proj4js for its coordinate transformation needs because nothing better exists.

While I can't say that the REST API solves this problem (we're not exactly giving you csmap.js here), we do try make the issue of transforming spatial data as minimal as possible in the REST API:
  • All data with spatial/geometric components whether queried in the above fashion or published via our GeoREST-style framework (which I'll elaborate in a future post) have transform-ability built-in as an option.
  • For everything else, we provide an endpoint for transforming a batch of coordinates from one coordinate system to another. Read on to find out how.
To transform a set of coordinates from one CS to another, you simply make a POST request like so:

POST http://servername/mapguide/rest/services/transformcoords
from = "LL84"
to = "WGS84.PseudoMercator"
coords = "-87.1 43.2,-87.2 43.3,-87.4 43.1"

This will give you a response which looks like this.

More cool stuff

If this post got you excited, then stay tuned because there's more where that came from in the next part.

Announcing: MapGuide Open Source 2.6 Preview Release 2

With FDO finally in sync with MapGuide in terms of VS compiler, we are now finally able to put out another preview release of MapGuide Open Source 2.6

Apart from a newer build of Fusion, this release has no new features over the first preview release, but includes updated web tier components:
  • PHP 5.5.3
  • Apache httpd 2.4.6
  • Apache Tomcat 7.0.42
All of MapGuide and its dependent components are now built with the same Visual Studio 2012 C++ compiler, meaning from an installer perspective, we no longer need to carry Visual C++ 2008 and 2010 runtime libraries as nothing we install is built with any of these compilers anymore.

All of these changes have a major impact on MapGuide installation, configuration and deployment, which is why we've put out this preview release, so that you (the interested user/tester) can help us check and verify that all our installation/configuration bases have been covered.

And in case this wasn't apparent, as a result of everything moving to VS 2012 we no longer support Windows XP or Windows Server 2003 as an installation target. If you need to use MapGuide on either one of these OSes, you'll have to stick with the 2.5 release.

Saturday, 8 February 2014

(Better?) MapGuide API Documentation

While googling for some class in the MapGuide API and forgetting I have a local doxygen-generated copy of the Web API documentation on hand, I stumbled onto this wonderful site call NuDoq which crawls all NuGet packages for relevant API documentation and provides a really slick interface for searching through classes/interfaces/properties/etc.

It obviously picked up the NuGet packages I've created for the .net binding to the MapGuide API and I have to say that the documentation generated by NuDoq is much more usable and accessible that our current doxygen-generated offering. And they even let you download the documentation for offline consumption too, always helpful to have. Sadly, there's still plenty of TODOs sprinkled through the transplanted API documentation, which is obviously telling us there are plenty of classes that still need documenting.

Wednesday, 5 February 2014

MapGuide tidbits: MgException proxy class in PHP

Here's a nice tidbit I discovered while building the mapguide-rest extension.

The MgException class in the PHP binding to the MapGuide API is also an Exception class. This means it carries its own PHP-land stack trace in addition to the MapGuide one.

What this means is when you catch an MgException in PHP code:

  • Calling GetStackTrace() gives you the C++ code stack trace on the MapGuide Server-side
  • Calling getTraceAsString() (because it's also a PHP Exception class), gives you the stack trace on the PHP side that triggered the MgException on the server-side.
Combine the two outputs and you get a very detailed series of events from both sides of the PHP-Native fence that explain how the MgException came to be thrown.

Tuesday, 4 February 2014

Introducing mapguide-rest: A new REST extension for MapGuide

Over the New Year, I've been thinking about how we can give MapGuide a proper REST API.

While mapguide4j was a nice experiment which explored this very idea, being written in Java ultimately was too much of a technological burden for me and for the user. The installation story is just horrible for users.
  • Install a JDK
  • Extract the mapguide4j zip to your install directory
  • Copy MapGuide dlls and jars (assuming you installed MapGuide with Java options enabled) into the mapguide4j directory
  • Start up the play framework and hope "Jarmageddon" doesn't ensue

While Java wasn't necessarily a bad choice, it was just too enterprise-y to offer a pleasant developer experience for me and installation experience for potential users. As a result, I've aborted that project and it is now relegated to being a big piece of sample code for anyone wondering how a MapGuide application could be built in Java.

At the same time, I also wanted to integrate features from GeoREST to provide a one-stop-shop REST API for MapGuide. Adding it to mapguide4j was not going to happen for reasons already stated.

So I went back to the drawing board, and the project known as mapguide-rest was born. So here's a little introduction.

mapguide-rest is a REST extension for MapGuide Open Source that is the amalgamation of ideas and features explored and implemented in the mapguide4j and GeoREST projects. It is written in PHP and works on both Windows and Linux versions of MapGuide. It provides the following services:
  • A REST API modeled on original discussions of a RESTful web service for MapGuide, and builds on top of what was already implemented and provided by mapguide4j.
  • A RESTful spatial data publishing framework similar to GeoREST. If you have used GeoREST before, this should be very similar to you.
In addition, it should also theoretically work on any release of MapGuide/AIMS (Windows or Linux) that bundles PHP 5.3 or newer, without having to muck around with any binaries, dlls or external dependencies although some bugs in earlier versions of MapGuide/AIMS may break or alter behaviour in some parts of the REST API.

For reliability, we recommend that you use mapguide-rest with the latest stable release of MapGuide (2.5.2). This is the version of MapGuide I have been building and testing on.

Installation of mapguide-rest is also a simple process (see Installation section below)


As mentioned, I wanted something similar to what I already had with mapguide4j, but not Java.

At the same time, I was primarily disappointed by the glacial (dead?) pace of GeoREST development. While GeoREST is bundled with every yearly release of AIMS, the most recent binary release on the Google Code site was 3 years ago.

Despite being open source, the codebase and build system/process for GeoREST just wasn't conductive to external contribution. For the longest time, I tried to get this thing to build in 64-bit and for recent releases of MapGuide Open Source, but with no instructions on how to build key 64-bit dependencies required by GeoREST (Google also failed me here), I just gave up and moved on to other productive activities. If you're using MapGuide Open Source, especially recent stable releases (like me), you're out of luck trying to get GeoREST working on such a release.

If we want the publishing capabilities of GeoREST with the RESTful API explored by mapguide4j, and do this in a language more developer-friendly and productive than C++, whose application is easy to install for the end user and has the necessary bindings to the MapGuide API then the logical conclusion of what to build mapguide-rest on top of was simple: Build it with PHP.

I know PHP might have a bad rap in some developer community circles and some might snicker at my choice to build mapguide-rest in this language, but in the context of MapGuide applications, PHP was the most logical choice for the following reasons:
  • It works on both Windows and Linux installations of MapGuide. Truly write once, run anywhere. I wasn't going to build yet another windows-only MapGuide web extension
  • PHP is always installed with MapGuide, regardless of your installation choice. It is after all, required by Fusion, the Site Administrator and other assorted web applications that are part of the MapGuide Web Tier. So whatever we build can be trusted to "just work" out of the box.
  • As a result of the above, the PHP binding to the MapGuide API is probably also the most "battle-hardened" of the 3 bindings we provide to the MapGuide API. If there were any stability or memory leak problems with the PHP binding, they would've been exposed by the many years of production use by Fusion, AJAX viewer and related PHP MapGuide applications and fixed appropriately.
  • Installation of PHP web applications is simple. Drop its directory into the www directory of your MapGuide installation and away you go. Web-server configuration can be handled via web.config or .htaccess files. No need to muck with IIS manager (for or editing Tomcat configuration files (for Java).
Installing mapguide-rest

UPDATE: For greater simplicity, just grab one of the release zip files.

Here's how you can install mapguide-rest.

Firstly, go to the project page on GitHub

Then grab a zip of the latest revision on master

Extract this zip archive to your www directory of your MapGuide installation. On windows, this is normally C:\Program Files\OSGeo\MapGuide\Web\www. On linux, this is /usr/local/mapguideopensource-x.y.z/webserverextensions/www where x.y.z is your version of MapGuide.

Rename this mapguide-rest-master directory to rest

If you're on Linux, you'll need to do the following:
If you're on IIS7 or above, install and enable the latest version of the Application Request Routing module for IIS. Once you have done this, you can then rename the web.config.iis file within to web.config to activate URL rewriting for the rest directory. On Linux, a .htaccess file is included that will activate mod_rewrite for that directory.

Once you have done the above steps, you can now start exploring everything that mapguide-rest has to offer:
If you are unable to set up URL rewriting, it just means you'll have an index.php in the above URLs, which will now look like this:
  • http://localhost/mapguide/rest/index.php/library/list.html
  • http://localhost/mapguide/rest/index.php/coordsys/categories.html
  • http://localhost/mapguide/rest/index.php/providers.html
  • http://localhost/mapguide/rest/index.php/data/property/.html

Want more information? 
  • Check out the (ever-evolving) wiki.
  • Ask a question on the mapguide-users mailing list.
  • Stay tuned to this blog as I will detail some of the cool stuff that can be done :)