Cookie information

This site does not use tracking cookies of any kind. It does use up to three cookies for other purposes though:

  • One cookie to track whether you've seen and accepted this cookie warning (valid for ten years)
  • One session coockie related to session information stored on the server side
  • The map tile servers on openstreetmap.org may also set a cookie of their own

The server side session tied to the session cookie is only used to remember previous choices when filling out the Create map form. The session does not store personalized data in any form.

The site will continue to function even when you choose to not accept any cookies, but you'll unfortunately also see this message again and again unless you at least accept the cookielaw_accepted cookie that gets sent when hitting the "OK" button below.

For further details see the sites privacy statemet

MapOSMatic remote rendering API

MapOSMatic is a web frontend for the OCitySMap renderer, which uses the Mapnik map rendering libary, Python and the CairoGraphics library to create decorated single page maps and multi page atlas-like booklets.

Originally this was a pure user centric web GUI, but recently a wish for using the infrastructure with different web frontends did come up.

So this HTTP API provides an alternative way to submit map rendering requests, and to retrieve additional data that may be needed on the way.

Requests and results are submitted as JSON documents, with the optional possibility to attach extra data files, like GPX tracks or Umap user created maps.

This documentation begins with describing the helper calls that provide lists of possible choices for different data fields, followed by the actual map rendering call and how to retrieve rendering status and results, and ends with example programs to access the API from different programming languages.

1. API calls

1.1. Paper Formats

1.1.1. Request URL

https://api.get-map.org/apis/paper_formats

1.1.2. Example result

{
    "Best fit": {
        "height": null,
        "width": null
    },
    "Din A4": {
        "height": 297,
        "width": 210
    },
    "US letter": {
        "height": 279,
        "width": 216
    }
}

1.2. Layouts

1.2.1. Request URL

https://api.get-map.org/apis/layouts

1.2.2. Example result

{
    "multi_page": {
        "description": "A multi-page layout.",
        "preview_url": "https://api.get-map.org/media/img/layout/multi_page.png"
    },
    "plain": {
        "description": "Full-page layout without index.",
        "preview_url": "https://api.get-map.org/media/img/layout/plain.png"
    },
    "single_page_index_bottom": {
        "description": "Full-page layout with the index at the bottom.",
        "preview_url": "https://api.get-map.org/media/img/layout/single_page_index_bottom.png"
    },
    "single_page_index_side": {
        "description": "Full-page layout with the index on the side.",
        "preview_url": "https://api.get-map.org/media/img/layout/single_page_index_side.png"
    }
}

1.3. Base Styles

1.3.1. Request URL

https://api.get-map.org/apis/styles

1.3.2. Example output

{
    "CartoOSM": {
        "annotation": "OpenStreetMap Carto standard style",
        "description": "CartoCSS OSM standard style",
        "preview_url": "https://api.get-map.org/media/img/style/CartoOSM.png"
    },
    "GermanCartoOSM": {
        "annotation": "German OSM style based on OSM Carto",
        "description": "German OSM style",
        "preview_url": "https://api.get-map.org/media/img/style/GermanCartoOSM.png"
    }
}

1.4. Overlay Styles

1.4.1. Request URL

https://api.get-map.org/apis/overlays

1.4.2. Example output

{
    "OpenRailwayMap_Overlay": {
        "annotation": "OpenRailwayMap overlay",
        "description": "OpenRailwayMap rail line overlay",
        "preview_url": "https://api.get-map.org/media/img/style/OpenRailwayMap_Overlay.jpg"
    },
    "Scale_Bar_overlay": {
        "annotation": "",
        "description": "Map scale bar"
        "preview_url": "https://api.get-map.org/media/img/style/Scale_Bar_overlay.jpg"
    }
 }

1.5. Job Stati

1.5.1. Request URL

https://api.get-map.org/apis/job_stati/

1.5.2. Example result

{
    "0": "Submitted",
    "1": "In progress",
    "2": "Done",
    "3": "Done w/o files",
    "4": "Cancelled"
}

1.6. Submitting a Job

1.6.1. Request URL

POST https://api.get-map.org/apis/jobs/

Expects render job named parameters as a JSON collection.

Possible parameters:

osmid

ID of an object in the osm2pgsql polygon table

bbox_top
bbox_bottom
bbox_left
bbox_right

Render area min. bounding box, may be extended to fit paper format

title

Text to put into the title box (default: "Untitled API Request")

language

locale to use for rendering (default: "en_US.UTF-8")

layout

Map layout to use (default: "plain")

style

Map base style to use (default: "CartoOSM")

overlays

List of overlays to put on top of base style (default: None)

paper_height

Paper height in mm

paper_width

Paper width in mm

paper_size

Predefined paper size to use (default: "Din A4" 210x297mm²)

orientation

Paper orientation: "portrait" or "landscape" when using a predefined paper size (default: "portrait")

import_url

URL pointing to an import file in one of the supported formats

track_url

URL pointing to a GPX track to download and print (deprecated)

umap_url

URL pointing to an Umap export file do download and print (deprecated)

It is also possible import files directly using a multipart/form-data POST request. In this case you have to submit the actual API JSON as a post parameter named "json", and add file fields using whatever field name you like.

Supported import file formats for now are GPX tracks, Umap map exports, and POI files as generated by the "Umgebungsplaene" neighborhood POI web application.

After successfully submitting a request you can either poll the job result API every once in a while until it either returns the "200 OK" status, or a 4xx error code. Or you can redirect a web client to the human readable result page listed in the returned "interactive" job parameter.

1.6.2. Return codes

202

Accepted when successfully submitted, "Location:" header will contain result URL

400

Bad request on request validation errors

1.6.3. Example requests

Content-type: application/json

{
    "title": "API Test",
    "bbox_bottom": 52.00,
    "bbox_left": 8.52,
    "bbox_right": 8.50,
    "bbox_top": 52.02
}
Content-Type: multipart/form-data; boundary=--XXXXXXXX

--XXXXXXXX
Content-Disposition: form-data; name="json"

{
    "title": "GPX Test",
    "paper_size": "Din A1"
}
--XXXXXXXX
Content-Disposition: form-data; name="file1"; filename="test.gpx"
Content-Type: application/gpx+xml

<?xml version="1.0" encoding="UTF-8"?>

<gpx version="1.1">
  <metadata>
    <name>GPX test</name>
  </metadata>
  <trk>
    <trkseg>
      <trkpt lat="52.00" lon="8.50" />
      <trkpt lat="52.02" lon="8.52" />
    </trkseg>
  </trk>
</gpx>
--XXXXXXXX
Content-Disposition: form-data; name="file2"; filename="test.umap"
Content-Type: application/json

{
  "type": "umap",
  "properties": {
    "name": "Umap test"
  },
  "layers": [
    {
      "type": "FeatureCollection",
      "features": [
        {
          "type": "Feature",
          "properties": {},
          "geometry": {
            "type": "Point",
            "coordinates": [
              8.535261,
              52.026977
            ]
          }
        }
      ],
      "_umap_options": {
        "name": "Layer 1"
      }
    }
  ]
}
--XXXXXXXX--

1.6.4. Example results

HTTP/1.1 202 Accepted
[...]
Location: /api/jobs/214
Content-Type: text/json

{
    "bbox_bottom": 52.01,
    "bbox_left": 8.52,
    "bbox_right": 8.50,
    "bbox_top": 52.02,
    "id": 214,
    "interactive": "https://api.get-map.org/maps/214"
    "language": "en_US.UTF-8",
    "layout": "plain",
    "nonce": "ESubNGmuwYGxPEGM",
    "paper_height_mm": 297,
    "paper_width_mm": 210,
    "status": 0,
    "styles": "CartoOSM",
    "title": "API Test"
}
HTTP/1.1 400 Bad Request
[...]
Content-Type: text/json

{
    "error": {
        "non_field_errors": [
            "No bounding box area or OsmID given"
        ]
    }
}

1.7. Checking Job results

1.7.1. Request Url

https://api.get-map.org/apis/jobs/

1.7.2. Return codes

200

OK when request has been processed successfully

202

Accepted when rendering is still in progress, "Location:" header will contain same URL again

410

Gone when a request had been processed successfuly in the past, but result files have since been purged to free file system space

400

Bad request when a request failed to render

1.7.3. Example result

HTTP/1.1 200 OK
[...]
Content-type: application/json

{
    "bbox_bottom": 52.01,
    "bbox_left": 8.53,
    "bbox_right": 8.49,
    "bbox_top": 52.02,
    "files":
    {
        "8bit.png": "https://api.get-map.org/results//000215_2018-09-12_23-14_GPX-test.8bit.png",
        "jpg": "https://api.get-map.org/results//000215_2018-09-12_23-14_GPX-test.jpg",
        "pdf": "https://api.get-map.org/results//000215_2018-09-12_23-14_GPX-test.pdf",
        "png": "https://api.get-map.org/results//000215_2018-09-12_23-14_GPX-test.png",
        "svgz": "https://api.get-map.org/results//000215_2018-09-12_23-14_GPX-test.svgz"
    }
    "id": 215,
    "language": "en_US.UTF-8",
    "layout": "plain",
    "paper_height_mm": 594,
    "paper_width_mm": 841,
    "queue_size": 0,
    "status": 2,
    "style": "CartoOSM",
    "title": "GPX test"
}

1.8. Cancel a submitted job

1.8.1. Request URL

POST https://api.get-map.org/apis/cancel_job

Expects id and nonce of job to cancel as a JSON collection.

Nonce is only returned when creating a job, so only the creator should be able to cancel a job but nobody else.

Required parameters:

id

ID of job to cancel

nonce

nonce string as returned on job creation call

1.8.2. Return codes

204

No content when job was cancelled successfully, or already no longer in a wait queue

400

Bad request when either id or nonce parameter are missing

403

Forbidden when the given nonce does not match the jobs actual nonce

404

Not found when no job with the given id exists

2. Example code

2.1. PHP

All examples in this script use the PEAR:HTTP_Request2 class for sending HTTP requests and receiving server replies.

2.1.1. Retrieve parameter choices

Here we are using the /paper_formats, /layouts, styles and overlays API calls to retrieve possible choices for all of these parameters, and their textual description where available.

parameters.php
<?php
require_once 'HTTP/Request2.php';

define('BASE_URL', 'https://api.get-map.org/apis/v1/');

function api_call($url) 
{
  $request = new HTTP_Request2(BASE_URL . $url);

  $request->setMethod(HTTP_Request2::METHOD_GET);
  
  $response = $request->send();
  $status = $response->getStatus();

  if ($status < 200 || $status > 299) {
          echo "invalid HTTP response to '$url': $status\n";
          echo $response->getBody();
          exit(3);
  }

  return json_decode($response->getBody());
}

echo "PAPER FORMATS:\n";
$paper_formats = api_call('paper_formats');
foreach ($paper_formats AS $name => $format) 
  printf("%-10s: %4dx%4d mm²\n", $name, $format->width, $format->height);

echo "\nLAYOUTS\n";
$layouts = api_call('layouts');
foreach ($layouts as $name => $layout) 
  printf("%-25s: %s\n", $name, $layout->description);

echo "\nSTYLES\n";
$styles = api_call('styles');
foreach ($styles as $name => $style) 
  printf("%-25s: %s\n", $name, $style->description);

echo "\nOVERLAYS\n";
$overlays = api_call('overlays');
foreach ($overlays as $name => $overlay) 
  printf("%-25s: %s\n", $name, $overlay->description);

2.1.2. Submitting a simple request

Now we are submitting a simple request, only setting the map title, and the bounding box of the area to display. We do not check for rendering to complete, but redirect the web client to the interactive result URL given as interactive in the returned JSON data.

This is the same result page as when you submit a map request manually via the standard web user interface, so this approach is suitable for interactive web applications:

simple-request.php
<?php
require_once 'HTTP/Request2.php';

define('BASE_URL', 'https://api.get-map.org/apis/v1/');

$data = ['title'       => 'PHP Test',
         'bbox_bottom' => 52.00,
         'bbox_top'    => 52.02,
         'bbox_left'   => 8.50,
         'bbox_right'  => 8.52
        ];

$request = new HTTP_Request2(BASE_URL . "jobs");

$request->setMethod(HTTP_Request2::METHOD_POST)
                ->setHeader('Content-type: application/json; charset=utf-8')
                ->setBody(json_encode($data));

$response = $request->send();
$status   = $response->getStatus();

if ($status < 200 || $status > 299) {
    header("Content-type: text/plain");
    print_r($response->getBody());
    exit;
}

$reply = json_decode($response->getBody());

header("Location: " . $reply->interactive);

2.1.3. Attaching a file

Now, to make things more interesting, we are going to attach a GPX file to our request. As the page title and the necessariy bounding box to fit all track data can be extracted from the file, if it is a valid GPX file, we do not need to pass any other data at all.

file-request.php
<?php
require_once 'HTTP/Request2.php';

define('BASE_URL', 'https://api.get-map.org/apis/v1/');
define('GPX_FILE', 'A1.gpx');

$data = [];

$request = new HTTP_Request2(BASE_URL . "jobs");

$request->setMethod(HTTP_Request2::METHOD_POST)
        ->addPostParameter('job', json_encode($data))
        ->addUpload('track', GPX_FILE, basename(GPX_FILE), 'application/gpx+xml');

$response = $request->send();
$status   = $response->getStatus();

echo "$status: ".$request->getBody()."\n";

if ($status < 200 || $status > 299) {
    header("Content-type: text/plain");
    print_r($response->getBody());
    exit;
}

$reply = json_decode($response->getBody());

echo "$status: ".$reply->interactive."\n";

2.1.4. Wait for rendering to complete

To have your application check for the rendering status yourself you need to poll the /jobs status page, adding the job id returned by the API. Please wait at least 15 seconds between status poll requests.

As long as the returned HTTP status is "202 Accepted" the request is either currently being processed, or still waiting in the job queue.

When the job has completed successfully "200 OK" will be returned, and the files object in the returned JSON result will contain a hash of produced file formats, and under what URL each of them can be retrieved.

In the example we retrieve the PDF version, and start the users preferred PDF viewer to present the result.

wait-for-result.php
<?php
require_once 'HTTP/Request2.php';

define('BASE_URL', 'https://api.get-map.org/apis/v1/');

function api_GET($url) 
{
  $request = new HTTP_Request2(BASE_URL . $url);

  $request->setMethod(HTTP_Request2::METHOD_GET);
  
  $response = $request->send();
  $status = $response->getStatus();

  if ($status < 200 || $status > 299) {
          echo "invalid HTTP response to '$url': $status\n";
          echo $response->getBody();
          exit(3);
  }

  return array($status, json_decode($response->getBody()));
}


$data = ['title'       => 'PHP Test',
         'bbox_bottom' => 52.00,
         'bbox_top'    => 52.02,
         'bbox_left'   => 8.50,
         'bbox_right'  => 8.52
        ];

$request = new HTTP_Request2(BASE_URL . "jobs");

$request->setMethod(HTTP_Request2::METHOD_POST)
                ->setHeader('Content-type: application/json; charset=utf-8')
                ->setBody(json_encode($data));

$response = $request->send();
$status   = $response->getStatus();

if ($status < 200 || $status > 299) {
    header("Content-type: text/plain");
    print_r($response->getBody());
    exit;
}

$reply = json_decode($response->getBody());

echo $reply->interactive."\n";

$job_url = "/jobs/" .  $reply->id;

    echo "waiting ... ";
    sleep(15);
    list($status, $reply) = api_GET($job_url);

    switch ($status) {
    case 200:
        $done = 1;
        break;
    case 202:
        switch($reply->status) {
        case 0:
            echo "still in queue\n";
            break;
        case 1:
            echo "now being rendered\n";
            break;
        default:
            echo "unexpected status: ".$reply->status."\n";
            break;
        }
        break;
    default:
        die("unexpected HTTP status: $status");
        break;
    }
}

$pdf = basename($reply->files->pdf);
copy($reply->files->pdf, $pdf);

system("xdg-open $pdf");
rm($pdf);

2.2. Python

To be done

2.3. Javascript

To be done, maybe. Due to the "same origin" restrictions this is low on my list …​