Dokumentation

Staedte Auswaehlen

Staedte nach Bundesland/Provinz abrufen, optimiert fuer Select-Dropdowns

Der /v1/select/cities-Endpunkt gibt eine leichtgewichtige Liste von Staedten zurueck, gefiltert nach Bundesland/Provinz, mit nur id- und name-Feldern, optimiert fuer Dropdown-Menues.

Endpunkt

GET https://api.countrydataapi.com/v1/select/cities

Authentifizierung

Fuegen Sie Ihren API-Schluessel als Abfrageparameter hinzu:

?apikey=ihr-api-schluessel

Ihr API-Schluessel ist wie ein Passwort, halten Sie ihn sicher. Holen Sie sich Ihren Schluessel aus dem Konto-Dashboard.

Abfrageparameter

Parameter Typ Erforderlich Beschreibung
apikey string Ja Ihr API-Authentifizierungsschluessel
state string Ja Bundesland-ID (vom /select/states-Endpunkt)
lang string Nein Sprachcode fuer Staedtenamen (Standard: de)

Unterstuetzte Sprachen

  • en - Englisch
  • es - Spanisch
  • pt - Portugiesisch
  • fr - Franzoesisch
  • de - Deutsch (Standard)
  • it - Italienisch

Anfrage-Beispiel

# Staedte fuer Bayern abrufen
curl "https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=66c7a6c9e4bda21f4ab0fae1&lang=de"

JavaScript (Fetch)

const API_KEY = 'ihr-api-schluessel';
const STATE_ID = '66c7a6c9e4bda21f4ab0fae1'; // Bayern

async function staedteLaden(bundeslandId) {
  const response = await fetch(
    `https://api.countrydataapi.com/v1/select/cities?apikey=${API_KEY}&state=${bundeslandId}&lang=de`
  );
  const data = await response.json();
  return data;
}

const staedte = await staedteLaden(STATE_ID);

JavaScript (Axios)

import axios from 'axios';

const response = await axios.get(
  'https://api.countrydataapi.com/v1/select/cities',
  {
    params: {
      apikey: 'ihr-api-schluessel',
      state: '66c7a6c9e4bda21f4ab0fae1',
      lang: 'de',
    },
  }
);

Python

import requests

response = requests.get(
    'https://api.countrydataapi.com/v1/select/cities',
    params={
        'apikey': 'ihr-api-schluessel',
        'state': '66c7a6c9e4bda21f4ab0fae1',
        'lang': 'de'
    }
)
data = response.json()

PHP

<?php
$apiKey = 'ihr-api-schluessel';
$stateId = '66c7a6c9e4bda21f4ab0fae1';
$url = "https://api.countrydataapi.com/v1/select/cities?apikey={$apiKey}&state={$stateId}&lang=de";

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
?>

Angular

// city.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

interface Stadt {
  id: string;
  name: string;
}

interface ApiResponse {
  success: boolean;
  data: Stadt[];
}

@Injectable({
  providedIn: 'root'
})
export class StadtService {
  private readonly API_KEY = 'ihr-api-schluessel';
  private readonly BASE_URL = 'https://api.countrydataapi.com/v1';

  constructor(private http: HttpClient) {}

  getStaedteNachBundesland(bundeslandId: string, lang: string = 'de'): Observable<Stadt[]> {
    const params = new HttpParams()
      .set('apikey', this.API_KEY)
      .set('state', bundeslandId)
      .set('lang', lang);

    return this.http.get<ApiResponse>(
      `${this.BASE_URL}/select/cities`,
      { params }
    ).pipe(
      map(response => response.data)
    );
  }
}

// city-select.component.ts
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { StadtService } from './city.service';

@Component({
  selector: 'app-city-select',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
    <div *ngIf="loading">Staedte werden geladen...</div>
    <div *ngIf="error" class="error">{{ error }}</div>
    <select
      *ngIf="!loading && !error"
      [(ngModel)]="selectedCity"
      (ngModelChange)="onCityChange($event)"
      [disabled]="!stateId"
    >
      <option value="">Stadt auswaehlen...</option>
      <option *ngFor="let city of cities" [value]="city.id">
        {{ city.name }}
      </option>
    </select>
  `
})
export class CitySelectComponent implements OnChanges {
  @Input() stateId: string = '';
  @Output() cityChange = new EventEmitter<string>();

  cities: any[] = [];
  selectedCity = '';
  loading = false;
  error: string | null = null;

  constructor(private stadtService: StadtService) {}

  ngOnChanges(changes: SimpleChanges) {
    if (changes['stateId'] && this.stateId) {
      this.loadCities();
    } else {
      this.cities = [];
      this.selectedCity = '';
    }
  }

  loadCities() {
    this.loading = true;
    this.error = null;

    this.stadtService.getStaedteNachBundesland(this.stateId, 'de').subscribe({
      next: (data) => {
        this.cities = data;
        this.loading = false;
      },
      error: (err) => {
        this.error = 'Fehler beim Laden der Staedte';
        this.loading = false;
      }
    });
  }

  onCityChange(cityId: string) {
    this.cityChange.emit(cityId);
  }
}

// Vollstaendiges kaskadierbares Formular-Beispiel
// address-form.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CountrySelectComponent } from './country-select.component';
import { StateSelectComponent } from './state-select.component';
import { CitySelectComponent } from './city-select.component';

@Component({
  selector: 'app-address-form',
  standalone: true,
  imports: [CommonModule, CountrySelectComponent, StateSelectComponent, CitySelectComponent],
  template: `
    <form>
      <div class="form-group">
        <label>Land</label>
        <app-country-select (countryChange)="onCountryChange($event)"></app-country-select>
      </div>

      <div class="form-group">
        <label>Bundesland</label>
        <app-state-select
          [countryId]="selectedCountry"
          (stateChange)="onStateChange($event)"
        ></app-state-select>
      </div>

      <div class="form-group">
        <label>Stadt</label>
        <app-city-select
          [stateId]="selectedState"
          (cityChange)="onCityChange($event)"
        ></app-city-select>
      </div>
    </form>
  `
})
export class AddressFormComponent {
  selectedCountry = '';
  selectedState = '';
  selectedCity = '';

  onCountryChange(countryId: string) {
    this.selectedCountry = countryId;
    this.selectedState = '';
    this.selectedCity = '';
  }

  onStateChange(stateId: string) {
    this.selectedState = stateId;
    this.selectedCity = '';
  }

  onCityChange(cityId: string) {
    this.selectedCity = cityId;
    console.log('Ausgewaehlt:', {
      land: this.selectedCountry,
      bundesland: this.selectedState,
      stadt: this.selectedCity
    });
  }
}

Antwortformat

Erfolgreiche Antwort (Bayern)

{
  "success": true,
  "data": [
    {
      "id": "66c7a6d1e4bda21f4ab34567",
      "name": "Muenchen"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34568",
      "name": "Nuernberg"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34569",
      "name": "Augsburg"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34570",
      "name": "Regensburg"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34571",
      "name": "Ingolstadt"
    }
    // ... Hunderte von Staedten
  ]
}

Antwortfelder

Feld Typ Beschreibung
success boolean Zeigt an, ob die Anfrage erfolgreich war
data array Array von Stadt-Objekten
data[].id string Eindeutiger Stadt-Identifikator (MongoDB ObjectId)
data[].name string Stadtname in der angeforderten Sprache

Fehlerantwort

{
  "success": false,
  "error": {
    "code": "MISSING_PARAMETER",
    "message": "Der erforderliche Parameter 'state' fehlt"
  }
}

Leeres Ergebnis

Wenn ein Bundesland keine Staedte in der Datenbank hat:

{
  "success": true,
  "data": []
}

Token-Verbrauch

Dieser Endpunkt verbraucht 1 Token pro Anfrage.

Wichtig: Einige Bundeslaender haben Tausende von Staedten. Erwaegen Sie die Implementierung von Paginierung oder Suchfunktionalitaet fuer bessere UX.

Vollstaendiges kaskadierendes Dropdown

HTML + JavaScript

<select id="country" onchange="bundeslaenderLaden(this.value)">
  <option value="">Land auswaehlen...</option>
</select>

<select id="state" onchange="staedteLaden(this.value)" disabled>
  <option value="">Bundesland auswaehlen...</option>
</select>

<select id="city" disabled>
  <option value="">Stadt auswaehlen...</option>
</select>

<script>
const API_KEY = 'ihr-api-schluessel';
const BASE_URL = 'https://api.countrydataapi.com/v1';

// Laender beim Seitenladen laden
async function laenderLaden() {
  const response = await fetch(`${BASE_URL}/select/countries?apikey=${API_KEY}&lang=de`);
  const { data } = await response.json();

  const select = document.getElementById('country');
  data.forEach(country => {
    select.add(new Option(country.name, country.id));
  });
}

async function bundeslaenderLaden(landId) {
  const stateSelect = document.getElementById('state');
  const citySelect = document.getElementById('city');

  // Zuruecksetzen
  stateSelect.innerHTML = '<option value="">Bundesland auswaehlen...</option>';
  citySelect.innerHTML = '<option value="">Stadt auswaehlen...</option>';
  stateSelect.disabled = true;
  citySelect.disabled = true;

  if (!landId) return;

  stateSelect.innerHTML = '<option value="">Wird geladen...</option>';

  const response = await fetch(
    `${BASE_URL}/select/states?apikey=${API_KEY}&country=${landId}&lang=de`
  );
  const { data } = await response.json();

  stateSelect.innerHTML = '<option value="">Bundesland auswaehlen...</option>';
  data.forEach(state => {
    stateSelect.add(new Option(state.name, state.id));
  });
  stateSelect.disabled = false;
}

async function staedteLaden(bundeslandId) {
  const citySelect = document.getElementById('city');

  // Zuruecksetzen
  citySelect.innerHTML = '<option value="">Stadt auswaehlen...</option>';
  citySelect.disabled = true;

  if (!bundeslandId) return;

  citySelect.innerHTML = '<option value="">Wird geladen...</option>';

  const response = await fetch(
    `${BASE_URL}/select/cities?apikey=${API_KEY}&state=${bundeslandId}&lang=de`
  );
  const { data } = await response.json();

  citySelect.innerHTML = '<option value="">Stadt auswaehlen...</option>';
  data.forEach(city => {
    citySelect.add(new Option(city.name, city.id));
  });
  citySelect.disabled = false;
}

// Laender beim Seitenladen laden
laenderLaden();
</script>

React-Komponente

import { useState, useEffect } from 'react';

function CitySelect({ stateId, onChange }) {
  const [cities, setCities] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!stateId) {
      setCities([]);
      return;
    }

    setLoading(true);
    fetch(
      `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${stateId}&lang=de`
    )
      .then(res => res.json())
      .then(({ data }) => {
        setCities(data || []);
        setLoading(false);
      })
      .catch(err => {
        console.error(err);
        setLoading(false);
      });
  }, [stateId]);

  return (
    <select
      onChange={e => onChange(e.target.value)}
      disabled={!stateId || loading}
    >
      <option value="">
        {loading ? 'Staedte werden geladen...' : 'Stadt auswaehlen...'}
      </option>
      {cities.map(city => (
        <option key={city.id} value={city.id}>
          {city.name}
        </option>
      ))}
    </select>
  );
}

export default CitySelect;

Vue-Komponente

<script setup>
import { ref, watch } from 'vue';

const props = defineProps(['stateId']);
const emit = defineEmits(['change']);

const cities = ref([]);
const loading = ref(false);

watch(() => props.stateId, async (stateId) => {
  if (!stateId) {
    cities.value = [];
    return;
  }

  loading.value = true;
  try {
    const response = await fetch(
      `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${stateId}&lang=de`
    );
    const { data } = await response.json();
    cities.value = data || [];
  } catch (err) {
    console.error(err);
  } finally {
    loading.value = false;
  }
});
</script>

<template>
  <select
    @change="emit('change', $event.target.value)"
    :disabled="!stateId || loading"
  >
    <option value="">
      {{ loading ? 'Staedte werden geladen...' : 'Stadt auswaehlen...' }}
    </option>
    <option v-for="city in cities" :key="city.id" :value="city.id">
      {{ city.name }}
    </option>
  </select>
</template>

Bundesland-spezifische Beispiele

Bayern (2000+ Staedte)

const BY_ID = '66c7a6c9e4bda21f4ab0fae1';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${BY_ID}`
);
// Gibt zurueck: Muenchen, Nuernberg, Augsburg, Regensburg, etc.

Nordrhein-Westfalen (300+ Staedte)

const NRW_ID = '66c7a6c9e4bda21f4ab0fae2';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${NRW_ID}`
);
// Gibt zurueck: Koeln, Duesseldorf, Dortmund, Essen, etc.

Baden-Wuerttemberg (1100+ Staedte)

const BW_ID = '66c7a6c9e4bda21f4ab0fae3';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${BW_ID}`
);
// Gibt zurueck: Stuttgart, Karlsruhe, Mannheim, Freiburg, etc.

Such-/Filter-Implementierung

Fuer Bundeslaender mit vielen Staedten, implementieren Sie clientseitige Suche:

function staedteFiltern(staedte, suchbegriff) {
  if (!suchbegriff) return staedte;

  return staedte.filter(stadt =>
    stadt.name.toLowerCase().includes(suchbegriff.toLowerCase())
  );
}

// Verwendung
const alleStaedte = await staedteLaden(bundeslandId);
const gefilterteStaedte = staedteFiltern(alleStaedte, 'Muen');
// Gibt zurueck: Muenchen, Muenster, etc.

Durchsuchbares Dropdown-Beispiel

<input
  type="text"
  id="city-search"
  placeholder="Staedte suchen..."
  oninput="staedteDropdownFiltern(this.value)"
>
<select id="city">
  <option value="">Stadt auswaehlen...</option>
</select>

<script>
let alleStaedte = [];

async function staedteLaden(bundeslandId) {
  const response = await fetch(
    `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${bundeslandId}`
  );
  const { data } = await response.json();
  alleStaedte = data;
  staedteAnzeigen(alleStaedte);
}

function staedteDropdownFiltern(suchbegriff) {
  const gefiltert = alleStaedte.filter(stadt =>
    stadt.name.toLowerCase().includes(suchbegriff.toLowerCase())
  );
  staedteAnzeigen(gefiltert);
}

function staedteAnzeigen(staedte) {
  const select = document.getElementById('city');
  select.innerHTML = '<option value="">Stadt auswaehlen...</option>';
  staedte.forEach(stadt => {
    select.add(new Option(stadt.name, stadt.id));
  });
}
</script>

Autocomplete-Implementierung

Fuer bessere UX, implementieren Sie Autocomplete:

<input
  type="text"
  id="city-autocomplete"
  placeholder="Tippen Sie um Staedte zu suchen..."
  list="cities-datalist"
>
<datalist id="cities-datalist">
  <!-- Dynamisch befuellt -->
</datalist>

<script>
async function staedteAutocompleteLaden(bundeslandId) {
  const response = await fetch(
    `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${bundeslandId}`
  );
  const { data } = await response.json();

  const datalist = document.getElementById('cities-datalist');
  datalist.innerHTML = '';
  data.forEach(stadt => {
    const option = document.createElement('option');
    option.value = stadt.name;
    option.dataset.id = stadt.id;
    datalist.appendChild(option);
  });
}
</script>

Caching-Strategie

Speichern Sie Staedte nach Bundesland zwischen, um API-Aufrufe zu minimieren:

const staedteCache = new Map();

async function getStaedte(bundeslandId) {
  // Zuerst Cache pruefen
  if (staedteCache.has(bundeslandId)) {
    return staedteCache.get(bundeslandId);
  }

  // Von API abrufen
  const response = await fetch(
    `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${bundeslandId}&lang=de`
  );
  const { data } = await response.json();

  // Im Cache speichern (Cache-Groesse begrenzen um Speicherprobleme zu vermeiden)
  if (staedteCache.size > 50) {
    const ersterSchluessel = staedteCache.keys().next().value;
    staedteCache.delete(ersterSchluessel);
  }
  staedteCache.set(bundeslandId, data);

  return data;
}

Performance-Optimierung

Lazy Loading

Staedte nur laden, wenn das Bundesland-Dropdown fokussiert wird:

stateSelect.addEventListener('focus', () => {
  if (!staedteGeladen) {
    staedteLaden(stateSelect.value);
    staedteGeladen = true;
  }
});

Virtuelles Scrollen

Fuer sehr grosse Listen verwenden Sie Virtual-Scrolling-Bibliotheken:

import { FixedSizeList } from 'react-window';

function VirtualCitySelect({ cities }) {
  const Row = ({ index, style }) => (
    <div style={style}>
      {cities[index].name}
    </div>
  );

  return (
    <FixedSizeList
      height={300}
      itemCount={cities.length}
      itemSize={35}
      width="100%"
    >
      {Row}
    </FixedSizeList>
  );
}

Fehlerbehandlung

Behandeln Sie Fehler immer angemessen:

async function staedteLaden(bundeslandId) {
  try {
    const response = await fetch(
      `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${bundeslandId}`
    );

    if (!response.ok) {
      throw new Error(`HTTP-Fehler! Status: ${response.status}`);
    }

    const result = await response.json();

    if (!result.success) {
      throw new Error(result.error?.message || 'API-Fehler');
    }

    return result.data;
  } catch (err) {
    console.error('Fehler beim Laden der Staedte:', err);
    alert('Fehler beim Laden der Staedte. Bitte versuchen Sie es erneut.');
    return [];
  }
}

Rate-Limits

  • Kostenloser Tarif: 100 Anfragen/Tag
  • Basis-Tarif: 1.000 Anfragen/Tag
  • Pro-Tarif: 10.000 Anfragen/Tag
  • Enterprise-Tarif: Unbegrenzt

Schauen Sie auf unsere Preisseite fuer weitere Details.

Haeufige Fehler

Fehlercode Beschreibung Loesung
INVALID_API_KEY API-Schluessel ist ungueltig Ueberpruefen Sie Ihren Schluessel im Konto-Dashboard
MISSING_PARAMETER state-Parameter fehlt Fuegen Sie die Bundesland-ID in die Anfrage ein
INVALID_STATE_ID Bundesland-ID-Format ist ungueltig Verwenden Sie eine gueltige MongoDB ObjectId von /select/states
QUOTA_EXCEEDED Taegliches Token-Limit erreicht Upgraden Sie Ihren Tarif oder warten Sie auf den Reset

Siehe die Fehlercode-Dokumentation fuer alle moeglichen Fehler.

Verwandte Endpunkte

Vollstaendige Integrationsleitfaeden

Brauchen Sie Hilfe?


Profi-Tipp: Fuer Bundeslaender mit 500+ Staedten erwaegen Sie die Implementierung eines durchsuchbaren Autocomplete-Dropdowns anstelle eines traditionellen Select-Elements. Dies verbessert die Benutzererfahrung und Performance erheblich.