Städte Auswählen

Städte nach Bundesland/Provinz abrufen, optimiert für Select-Dropdowns

Der /v1/select/cities-Endpunkt gibt eine leichtgewichtige Liste von Städten zurück, gefiltert nach Bundesland/Provinz, mit nur id- und name-Feldern, optimiert für Dropdown-Menüs.

Endpunkt

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

Authentifizierung

Fügen Sie Ihren API-Schlüssel als Abfrageparameter hinzu:

?apikey=ihr-api-schluessel

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

Abfrageparameter

Parameter Typ Erforderlich Beschreibung
apikey string Ja Ihr API-Authentifizierungsschlüssel
state string Ja Bundesland-ID (vom /select/states-Endpunkt)
lang string Nein Sprachcode für Städtenamen (Standard: de)

Unterstützte Sprachen

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

Anfrage-Beispiel

# Städte für 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">Städte werden geladen...</div>
    <div *ngIf="error" class="error">{{ error }}</div>
    <select
      *ngIf="!loading && !error"
      [(ngModel)]="selectedCity"
      (ngModelChange)="onCityChange($event)"
      [disabled]="!stateId"
    >
      <option value="">Stadt auswählen...</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 Städte';
        this.loading = false;
      }
    });
  }

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

// Vollständiges 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('Ausgewählt:', {
      land: this.selectedCountry,
      bundesland: this.selectedState,
      stadt: this.selectedCity
    });
  }
}

Antwortformat

Erfolgreiche Antwort (Bayern)

{
  "success": true,
  "data": [
    {
      "id": "66c7a6d1e4bda21f4ab34567",
      "name": "München"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34568",
      "name": "Nürnberg"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34569",
      "name": "Augsburg"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34570",
      "name": "Regensburg"
    },
    {
      "id": "66c7a6d1e4bda21f4ab34571",
      "name": "Ingolstadt"
    }
    // ... Hunderte von Städten
  ]
}

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 Städte in der Datenbank hat:

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

Token-Verbrauch

Dieser Endpunkt verbraucht 1 Token pro Anfrage.

Wichtig: Einige Bundesländer haben Tausende von Städten. Erwägen Sie die Implementierung von Paginierung oder Suchfunktionalität für bessere UX.

Vollständiges kaskadierendes Dropdown

HTML + JavaScript

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

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

<select id="city" disabled>
  <option value="">Stadt auswählen...</option>
</select>

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

// Länder 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');

  // Zurücksetzen
  stateSelect.innerHTML = '<option value="">Bundesland auswählen...</option>';
  citySelect.innerHTML = '<option value="">Stadt auswählen...</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 auswählen...</option>';
  data.forEach(state => {
    stateSelect.add(new Option(state.name, state.id));
  });
  stateSelect.disabled = false;
}

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

  // Zurücksetzen
  citySelect.innerHTML = '<option value="">Stadt auswählen...</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 auswählen...</option>';
  data.forEach(city => {
    citySelect.add(new Option(city.name, city.id));
  });
  citySelect.disabled = false;
}

// Länder 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 ? 'Städte werden geladen...' : 'Stadt auswählen...'}
      </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 ? 'Städte werden geladen...' : 'Stadt auswählen...' }}
    </option>
    <option v-for="city in cities" :key="city.id" :value="city.id">
      {{ city.name }}
    </option>
  </select>
</template>

Bundesland-spezifische Beispiele

Bayern (2000+ Städte)

const BY_ID = '66c7a6c9e4bda21f4ab0fae1';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${BY_ID}`
);
// Gibt zurück: München, Nürnberg, Augsburg, Regensburg, etc.

Nordrhein-Westfalen (300+ Städte)

const NRW_ID = '66c7a6c9e4bda21f4ab0fae2';
const response = await fetch(
  `https://api.countrydataapi.com/v1/select/cities?apikey=ihr-api-schluessel&state=${NRW_ID}`
);
// Gibt zurück: Köln, Düsseldorf, Dortmund, Essen, etc.

Baden-Württemberg (1100+ Städte)

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

Such-/Filter-Implementierung

Für Bundesländer mit vielen Städten, 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, 'Mün');
// Gibt zurück: München, Münster, etc.

Durchsuchbares Dropdown-Beispiel

<input
  type="text"
  id="city-search"
  placeholder="Städte suchen..."
  oninput="staedteDropdownFiltern(this.value)"
>
<select id="city">
  <option value="">Stadt auswählen...</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 auswählen...</option>';
  staedte.forEach(stadt => {
    select.add(new Option(stadt.name, stadt.id));
  });
}
</script>

Autocomplete-Implementierung

Für bessere UX, implementieren Sie Autocomplete:

<input
  type="text"
  id="city-autocomplete"
  placeholder="Tippen Sie um Städte zu suchen..."
  list="cities-datalist"
>
<datalist id="cities-datalist">
  <!-- Dynamisch befüllt -->
</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 Städte nach Bundesland zwischen, um API-Aufrufe zu minimieren:

const staedteCache = new Map();

async function getStaedte(bundeslandId) {
  // Zuerst Cache prüfen
  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-Größe 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

Städte nur laden, wenn das Bundesland-Dropdown fokussiert wird:

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

Virtuelles Scrollen

Für sehr große 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 Städte:', err);
    alert('Fehler beim Laden der Städte. 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 für weitere Details.

Häufige Fehler

Fehlercode Beschreibung Lösung
INVALID_API_KEY API-Schlüssel ist ungültig Überprüfen Sie Ihren Schlüssel im Konto-Dashboard
MISSING_PARAMETER state-Parameter fehlt Fügen Sie die Bundesland-ID in die Anfrage ein
INVALID_STATE_ID Bundesland-ID-Format ist ungültig Verwenden Sie eine gültige MongoDB ObjectId von /select/states
QUOTA_EXCEEDED Tägliches Token-Limit erreicht Upgraden Sie Ihren Tarif oder warten Sie auf den Reset

Siehe die Fehlercode-Dokumentation für alle möglichen Fehler.

Verwandte Endpunkte

Vollständige Integrationsleitfäden

Brauchen Sie Hilfe?


Profi-Tipp: Für Bundesländer mit 500+ Städten erwägen Sie die Implementierung eines durchsuchbaren Autocomplete-Dropdowns anstelle eines traditionellen Select-Elements. Dies verbessert die Benutzererfahrung und Performance erheblich.