Martin is a PostGIS vector tiles server suitable for large databases. Martin is written in Rust using Actix web framework.
- Requirements
- Installation
- Usage
- Using with Mapbox GL JS
- Table Sources
- Function Sources
- Command-line Interface
- Environment Variables
- Configuration File
- Using with Docker
- Using with Nginx
- Building from Source
- Debugging
- Development
Martin requires PostGIS >= 2.4.0.
You can download martin from Github releases page.
If you are using macOS and Homebrew you can install martin using Homebrew tap.
brew tap urbica/tap
brew install martinMartin requires a database connection string. It can be passed as a command-line argument or as a DATABASE_URL environment variable.
martin postgres://postgres@localhost/dbMapbox GL JS is a JavaScript library for interactive, customizable vector maps on the web. It takes map styles that conform to the Mapbox Style Specification, applies them to vector tiles that conform to the Mapbox Vector Tile Specification, and renders them using WebGL.
You can add a layer to the map and specify martin TileJSON endpoint as a vector source URL. You should also specify a source-layer property. For Table Sources it is {schema_name}.{table_name} by default.
map.addLayer({
id: 'public.points',
type: 'circle',
source: {
type: 'vector',
url: 'http://localhost:3000/public.points.json'
},
'source-layer': 'public.points'
});Table Source is a database table which can be used to query vector tiles. When started, martin will go through all spatial tables in the database and build a list of table sources. A table should have at least one geometry column with non-zero SRID. All other table columns will be represented as properties of a vector tile feature.
Table Sources list endpoint is available at /index.json
curl localhost:3000/index.jsonTable Source TileJSON endpoint is available at /{schema_name}.{table_name}.json.
For example, points table in public schema will be available at /public.points.json
curl localhost:3000/public.points.jsonTable Source tiles endpoint is available at /{schema_name}.{table_name}/{z}/{x}/{y}.pbf
For example, points table in public schema will be available at /public.points/{z}/{x}/{y}.pbf
curl localhost:3000/public.points/0/0/0.pbfFunction Source is a database function which can be used to query vector tiles. When started, martin will look for the functions with a suitable signature. A function that takes z integer, x integer, y integer, and query_params json and returns bytea, can be used as a Function Source.
| Argument | Type | Description |
|---|---|---|
| z | integer | Tile zoom parameter |
| x | integer | Tile x parameter |
| y | integer | Tile y parameter |
| query_params | json | Query string parameters |
Hint: You may want to use TileBBox function to generate bounding-box geometry of the area covered by a tile.
Here is an example of a function that can be used as a Function Source.
CREATE OR REPLACE FUNCTION public.function_source(z integer, x integer, y integer, query_params json) RETURNS BYTEA AS $$
DECLARE
bounds GEOMETRY(POLYGON, 3857) := TileBBox(z, x, y, 3857);
mvt BYTEA;
BEGIN
SELECT INTO mvt ST_AsMVT(tile, 'public.function_source', 4096, 'geom') FROM (
SELECT
ST_AsMVTGeom(geom, bounds, 4096, 64, true) AS geom
FROM public.table_source
WHERE geom && bounds
) as tile WHERE geom IS NOT NULL;
RETURN mvt;
END
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
Function Sources list endpoint is available at /rpc/index.json
curl localhost:3000/rpc/index.jsonFunction Source TileJSON endpoint is available at /rpc/{schema_name}.{function_name}.json
For example, points function in public schema will be available at /rpc/public.points.json
curl localhost:3000/rpc/public.points.jsonFunction Source tiles endpoint is available at /rpc/{schema_name}.{function_name}/{z}/{x}/{y}.pbf
For example, points function in public schema will be available at /rpc/public.points/{z}/{x}/{y}.pbf
curl localhost:3000/rpc/public.points/0/0/0.pbfYou can configure martin using command-line interface
Usage:
martin [options] [<connection>]
martin -h | --help
martin -v | --version
Options:
-h --help Show this screen.
-v --version Show version.
--workers=<n> Number of web server workers.
--pool_size=<n> Maximum connections pool size [default: 20].
--keep_alive=<n> Connection keep alive timeout [default: 75].
--listen_addresses=<n> The socket address to bind [default: 0.0.0.0:3000].
--config=<path> Path to config file.You can also configure martin using environment variables
| Environment variable | Example | Description |
|---|---|---|
| DATABASE_URL | postgres://postgres@localhost/db | postgres database connection |
| DATABASE_POOL_SIZE | 20 | maximum connections pool size |
| WORKER_PROCESSES | 8 | number of web server workers |
| KEEP_ALIVE | 75 | connection keep alive timeout |
If you don't want to expose all of your tables and functions, you can list your sources in a configuration file. To start martin with a configuration file you need to pass a path to a file with a --config argument.
martin --config config.yamlYou can find an example of a configuration file here.
# Maximum connections pool size [default: 20]
pool_size: 20
# Connection keep alive timeout [default: 75]
keep_alive: 75
# Number of web server workers
worker_processes: 8
# The socket address to bind [default: 0.0.0.0:3000]
listen_addresses: '0.0.0.0:3000'
# associative arrays of table sources
table_sources:
public.table_source:
# table source id
id: public.table_source
# table schema
schema: public
# table name
table: table_source
# geometry column name
geometry_column: geom
# geometry srid
srid: 4326
# tile extent in tile coordinate space
extent: 4096
# buffer distance in tile coordinate space to optionally clip geometries
buffer: 64
# boolean to control if geometries should be clipped or encoded as is
clip_geom: true
# geometry type
geometry_type: GEOMETRY
# list of columns, that should be encoded as a tile properties
properties:
gid: int4
# associative arrays of function sources
function_sources:
public.function_source:
# function source id
id: public.function_source
# schema name
schema: public
# function name
function: function_sourceYou can use official Docker image urbica/martin
docker run \
-p 3000:3000 \
-e DATABASE_URL=postgres://postgres@localhost/db \
urbica/martinIf you are running PostgreSQL instance on localhost, you have to change network settings to allow the Docker container to access the localhost network.
For Linux, add the --net=host flag to access the localhost PostgreSQL service.
docker run \
--net=host \
-p 3000:3000 \
-e DATABASE_URL=postgres://postgres@localhost/db \
urbica/martinFor macOS, use host.docker.internal as hostname to access the localhost PostgreSQL service.
docker run \
-p 3000:3000 \
-e DATABASE_URL=postgres://postgres@host.docker.internal/db \
urbica/martinFor Windows, use docker.for.win.localhost as hostname to access the localhost PostgreSQL service.
docker run \
-p 3000:3000 \
-e DATABASE_URL=postgres://postgres@docker.for.win.localhost/db \
urbica/martinIf you are running martin behind nginx proxy, you may want to rewrite request URL, to properly handle tile urls in TileJSON endpoints.
location ~ /tiles/(?<fwd_path>.*) {
proxy_set_header X-Rewrite-URL $request_uri;
proxy_pass http://martin:3000/$fwd_path$is_args$args;
}You can clone the repository and build martin using cargo package manager.
git clone git@github.com:urbica/martin.git
cd martin
cargo build --releaseThe binary will be available at ./target/release/martin.
cd ./target/release/
./martin postgres://postgres@localhost/dbLog levels are controlled on a per-module basis, and by default all logging is disabled except for errors. Logging is controlled via the RUST_LOG environment variable. The value of this environment variable is a comma-separated list of logging directives.
This will enable verbose logging for the actix_web module and enable debug logging for the martin and postgres modules:
export RUST_LOG=actix_web=info,martin=debug,postgres=debug
martin postgres://postgres@localhost/dbInstall project dependencies and check if all the tests are running.
cargo test
cargo run