Setting up basic API Structure
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
/// Small helper that makes reading .Net json payloads defensive.
|
||||
///
|
||||
/// The backend is still in development, so property names might arrive in
|
||||
/// PascalCase or camelCase and single properties might be missing. These
|
||||
/// helpers keep the dto factories short and readable.
|
||||
class JsonReader {
|
||||
const JsonReader._();
|
||||
|
||||
/// Looks a key up, ignoring casing differences between .Net and Dart.
|
||||
static dynamic value(Map<String, dynamic> json, String key) {
|
||||
if (json.containsKey(key)) {
|
||||
return json[key];
|
||||
}
|
||||
|
||||
final lowerKey = key.toLowerCase();
|
||||
for (final entry in json.entries) {
|
||||
if (entry.key.toLowerCase() == lowerKey) {
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static String requireString(Map<String, dynamic> json, String key) {
|
||||
final raw = value(json, key);
|
||||
if (raw == null) {
|
||||
throw FormatException('Missing required property "$key".');
|
||||
}
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
static String? optionalString(Map<String, dynamic> json, String key) {
|
||||
final raw = value(json, key);
|
||||
return raw?.toString();
|
||||
}
|
||||
|
||||
static DateTime requireDateTime(Map<String, dynamic> json, String key) {
|
||||
final parsed = optionalDateTime(json, key);
|
||||
if (parsed == null) {
|
||||
throw FormatException('Missing or invalid date property "$key".');
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static DateTime? optionalDateTime(Map<String, dynamic> json, String key) {
|
||||
final raw = value(json, key);
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
if (raw is DateTime) {
|
||||
return raw;
|
||||
}
|
||||
return DateTime.tryParse(raw.toString());
|
||||
}
|
||||
|
||||
static bool? optionalBool(Map<String, dynamic> json, String key) {
|
||||
final raw = value(json, key);
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
if (raw is bool) {
|
||||
return raw;
|
||||
}
|
||||
final text = raw.toString().toLowerCase();
|
||||
if (text == 'true' || text == '1') {
|
||||
return true;
|
||||
}
|
||||
if (text == 'false' || text == '0') {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static int? optionalInt(Map<String, dynamic> json, String key) {
|
||||
final raw = value(json, key);
|
||||
if (raw == null) {
|
||||
return null;
|
||||
}
|
||||
if (raw is int) {
|
||||
return raw;
|
||||
}
|
||||
if (raw is num) {
|
||||
return raw.toInt();
|
||||
}
|
||||
return int.tryParse(raw.toString());
|
||||
}
|
||||
|
||||
/// Maps a json array onto a list of models, tolerating a missing property.
|
||||
static List<T> list<T>(
|
||||
Map<String, dynamic> json,
|
||||
String key,
|
||||
T Function(Map<String, dynamic> json) fromJson,
|
||||
) {
|
||||
final raw = value(json, key);
|
||||
if (raw is! List) {
|
||||
return <T>[];
|
||||
}
|
||||
return raw
|
||||
.whereType<Map>()
|
||||
.map((entry) => fromJson(Map<String, dynamic>.from(entry)))
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
/// Resolves a .Net enum that can arrive either as its name or as its index.
|
||||
static T enumValue<T>(
|
||||
Map<String, dynamic> json,
|
||||
String key,
|
||||
List<T> values,
|
||||
String Function(T value) nameOf,
|
||||
T fallback,
|
||||
) {
|
||||
final raw = value(json, key);
|
||||
if (raw == null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (raw is num) {
|
||||
final index = raw.toInt();
|
||||
if (index >= 0 && index < values.length) {
|
||||
return values[index];
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
final text = raw.toString().trim().toLowerCase();
|
||||
for (final candidate in values) {
|
||||
if (nameOf(candidate).toLowerCase() == text) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
final index = int.tryParse(text);
|
||||
if (index != null && index >= 0 && index < values.length) {
|
||||
return values[index];
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user