InfraNode.dev

InfraNode mit Java: HttpClient und OpenAPI Generator

Tutorial: offene Daten deutscher Großstädte aus Java abrufen, mit dem eingebauten java.net.http.HttpClient und Jackson oder mit einem typisierten Client, den der OpenAPI Generator aus der offiziellen Spec erzeugt. Ohne API-Schlüssel.

Weg 1: HttpClient und Jackson

Ab Java 11 bringt das JDK mit java.net.http.HttpClient alles für HTTP mit. Für das JSON reicht Jackson als einzige Abhängigkeit (Maven):

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

Jede Antwort hat dieselbe Hülle: die Fachdaten unter data, den Quellenstatus unter meta. Bei einem Datensatz liegen die Messwerte in data.payload, die Quellenangabe in data.attribution.

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Main {
    private static final String BASE = "https://infranode.dev/api/v1";
    private static final HttpClient HTTP = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();
    private static final ObjectMapper JSON = new ObjectMapper();

    static JsonNode get(String path) throws Exception {
        HttpRequest req = HttpRequest.newBuilder(URI.create(BASE + path))
                .header("Accept", "application/json")
                .timeout(Duration.ofSeconds(30))
                .build();
        HttpResponse<String> res = HTTP.send(req, HttpResponse.BodyHandlers.ofString());
        if (res.statusCode() != 200) {
            throw new IllegalStateException("HTTP " + res.statusCode() + ": " + res.body());
        }
        return JSON.readTree(res.body());
    }

    public static void main(String[] args) throws Exception {
        JsonNode data = get("/cities/berlin/weather").path("data");
        System.out.println(data.path("payload").path("temperature_c").asDouble() + " °C");
        System.out.println("Quelle: " + data.path("attribution").path("text").asText());

        JsonNode cities = get("/cities").path("data");
        System.out.println(cities.size() + " Städte");
    }
}

Jeder Datensatz trägt seine eigene attribution (Quelle und Lizenz-URL). Die Open-Data-Lizenzen verlangen die Nennung, zeige sie also deinen Nutzern an. Welche Datenarten es gibt, steht im Datenkatalog.

Weg 2: typisierter Client per OpenAPI Generator

Wer Klassen statt JsonNode möchte, erzeugt den Client aus der offiziellen Spec unter https://infranode.dev/openapi.json. Mit Docker ist keine lokale Installation des Generators nötig:

docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v7.10.0 generate \
  -i https://infranode.dev/openapi.json \
  -g java --library native \
  -o /local/infranode-client \
  --api-package dev.infranode.api \
  --model-package dev.infranode.model \
  --invoker-package dev.infranode.client

--library native baut auf dem JDK-HttpClient auf und zieht nur Jackson nach. Danach den Client ins lokale Maven-Repository installieren:

cd infranode-client
mvn install -DskipTests

Den erzeugten Client bindest du über seine Koordinaten aus der pom.xml ein (Standard: org.openapitools:openapi-java-client). Jede Datenart hat eine eigene Methode, z. B. getCityWeather, getCityParking oder getCityCharging:

import dev.infranode.api.CitiesApi;
import dev.infranode.client.ApiClient;
import dev.infranode.client.ApiException;
import dev.infranode.model.CanonicalRecord;
import dev.infranode.model.WeatherPayload;

public class Wetter {
    public static void main(String[] args) throws ApiException {
        ApiClient client = new ApiClient();
        client.updateBaseUri("https://infranode.dev");
        CitiesApi cities = new CitiesApi(client);

        CanonicalRecord rec = cities.getCityWeather("berlin").getData();
        WeatherPayload w = rec.getPayload().getWeatherPayload();
        System.out.println(w.getTemperatureC() + " °C");
        System.out.println("Quelle: " + rec.getAttribution().getText());

        // Fehler (404 unbekannte Stadt, 503 Quelle down) kommen als ApiException
        try {
            cities.getCityWeather("essen");
        } catch (ApiException e) {
            System.out.println("HTTP " + e.getCode());
        }
    }
}

payload ist eine Union über alle Payload-Arten, unterschieden am Feld kind. Den passenden Typ holst du mit dem Getter der Art (getWeatherPayload(), getParkingPayload(), ...) oder allgemein mit getActualInstance().

Weiterführend

Endpunkte und Parameter: API-Referenz. Listen-Endpunkte paginieren optional, siehe Paginierung. Für KI-Agenten gibt es den InfraNode-MCP-Server.

Häufige Fragen

Gibt es ein offizielles Java-SDK?
Nein, ein eigenes Java-Paket gibt es nicht. Die API ist schlank genug für den eingebauten HttpClient, und für typisierte Klassen erzeugt der OpenAPI Generator einen vollständigen Client aus https://infranode.dev/openapi.json.
Brauche ich einen API-Schlüssel?
Nein. Die InfraNode-API ist kostenlos und keylos. Kein Key, keine Registrierung.
Welche Java-Version brauche ich?
Java 11 oder neuer. java.net.http.HttpClient gehört seit Java 11 zum JDK, der generierte Client ist ebenfalls auf Java 11 eingestellt.
Funktioniert das auch mit Kotlin oder Spring?
Ja. Der generierte Java-Client läuft in Kotlin unverändert. Der OpenAPI Generator kennt außerdem eigene Ziele wie -g kotlin oder --library resttemplate und webclient für Spring.