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());
}
}