rufen method

Future<Map<String, dynamic>> rufen(
  1. String name, {
  2. Map<String, dynamic> params = const <String, dynamic>{},
})

Einen Endpunkt rufen. null-Werte in params fallen weg, damit das Backend "nicht gesetzt" nicht als ausdrueckliche Angabe missversteht.

Implementation

Future<Map<String, dynamic>> rufen(
  String name, {
  Map<String, dynamic> params = const <String, dynamic>{},
}) async {
  final nutzlast = <String, dynamic>{};
  params.forEach((schluessel, wert) {
    if (wert != null) nutzlast[schluessel] = wert;
  });

  // Ausserhalb des try: ein nicht serialisierbarer Parameter ist ein
  // Programmierfehler und keine Netzstoerung.
  final String rumpf = jsonEncode(<String, dynamic>{'params': nutzlast});

  final http.Response antwort;
  try {
    antwort = await _http
        .post(
          Uri.parse('$baseUrl/$name'),
          headers: <String, String>{
            'Content-Type': 'application/json',
            'Authorization': 'Bearer $_schluessel',
          },
          body: rumpf,
        )
        .timeout(_frist);
  } on TimeoutException catch (e) {
    // Getrennt vom Netzfehler: die Anfrage war draussen, der Ausgang ist
    // unbekannt. Ueber `createPartnerCustomer` kann der Betrieb laengst
    // angelegt sein -- mit `idempotencyKey` ist die Wiederholung dann
    // folgenlos, ohne ihn nicht.
    throw KasseneckHttpError(name, 0, KasseneckHttpError.zeitablauf, causeType: '${e.runtimeType}');
  } on Object catch (e) {
    // Nur der Typ, nie die Meldung: die kann eine Adresse tragen. Der
    // Schluessel faehrt in der Kopfzeile und ist davon nicht betroffen.
    throw KasseneckHttpError(name, 0, KasseneckHttpError.netz, causeType: '${e.runtimeType}');
  }

  Object? roh;
  try {
    roh = jsonDecode(antwort.body);
  } on FormatException {
    // Typischer Fall: der Aufruf landete mangels Weiterleitung auf der
    // HTML-Seite -- HTTP 200, aber kein JSON.
    throw KasseneckHttpError(name, antwort.statusCode, 'not-json');
  }
  if (roh is! Map) throw KasseneckHttpError(name, antwort.statusCode, 'missing-status');
  final huelle = Map<String, dynamic>.from(roh);
  if (huelle['status'] == 'success') {
    final daten = huelle['data'];
    if (daten == null) return <String, dynamic>{};
    if (daten is! Map) throw KasseneckHttpError(name, antwort.statusCode, 'data-not-object');
    return Map<String, dynamic>.from(daten);
  }
  final meldung = huelle['message'];
  // Die Beilage wird gesiebt und nicht durchgereicht -- flach, klein,
  // bezeichner-foermig benannt, und kein Wert, der mit dem gesendeten
  // Schluessel ueberlappt (siehe fehlerDetails).
  final details = fehlerDetails(huelle['data'], <String>[_schluessel]);
  final code = details['code'];
  throw KasseneckApiError(
    name,
    meldung is String && meldung.isNotEmpty ? meldung : 'Der Aufruf ist fehlgeschlagen.',
    code: code is String && RegExp(r'^[A-Za-z][A-Za-z0-9_./-]{0,63}$').hasMatch(code) ? code : null,
    details: details,
  );
}