Skip to content

Java Quickstart

Server-side: tile proxy, geocoding. JDK 17+.

Maven (pom.xml)

xml
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.17.0</version>
</dependency>

Geocoding client (java.net.http)

java
package com.mapsfordevs.client;

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.List;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class MapsForDevsClient {
    private static final String BASE = "https://api.mapsfordevs.com";
    private final HttpClient http = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(5))
            .build();
    private final ObjectMapper json = new ObjectMapper();
    private final String apiKey;

    public MapsForDevsClient(String apiKey) { this.apiKey = apiKey; }

    public List<GeocodeItem> geocode(String query, String country, int limit) throws Exception {
        StringBuilder url = new StringBuilder(BASE)
                .append("/geocode/forward?q=")
                .append(URLEncoder.encode(query, StandardCharsets.UTF_8))
                .append("&limit=").append(limit);
        if (country != null) url.append("&country=").append(country);

        HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create(url.toString()))
                .header("Authorization", "Bearer " + apiKey)
                .timeout(Duration.ofSeconds(10))
                .GET()
                .build();

        HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
        JsonNode body = json.readTree(resp.body());
        if (!body.path("ok").asBoolean()) {
            throw new RuntimeException(body.path("error").asText());
        }
        return json.convertValue(body.path("items"),
                json.getTypeFactory().constructCollectionType(List.class, GeocodeItem.class));
    }

    public record GeocodeItem(double lat, double lng, String label, double confidence, String type) {}
}

Tile proxy (Spring Boot)

java
import org.springframework.web.bind.annotation.*;
import org.springframework.http.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.*;
import java.time.Instant;
import java.util.HexFormat;

@RestController
public class TileProxyController {
    private static final String KEY    = System.getenv("MFD_SRV_KEY");
    private static final String SECRET = System.getenv("MFD_SRV_SECRET");
    private final HttpClient http = HttpClient.newHttpClient();

    @GetMapping(value = "/tiles/{z}/{x}/{y}.pbf", produces = "application/x-protobuf")
    public ResponseEntity<byte[]> tile(@PathVariable int z, @PathVariable int x, @PathVariable int y) throws Exception {
        String path = "/tiles/" + z + "/" + x + "/" + y + ".pbf";
        String ts   = String.valueOf(Instant.now().getEpochSecond());

        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(SECRET.getBytes(), "HmacSHA256"));
        String sig = HexFormat.of().formatHex(mac.doFinal(("GET\n" + path + "\n" + ts).getBytes()));

        HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create("https://tiles.mapsfordevs.com" + path))
                .header("Authorization", "Bearer " + KEY)
                .header("X-MFD-Timestamp", ts)
                .header("X-MFD-Signature", sig)
                .GET().build();

        HttpResponse<byte[]> resp = http.send(req, HttpResponse.BodyHandlers.ofByteArray());
        return ResponseEntity.status(resp.statusCode())
                .cacheControl(CacheControl.maxAge(java.time.Duration.ofDays(1)).cachePublic())
                .body(resp.body());
    }
}