coerce<T> function
Converts one raw string from a path segment, query value, header, or form
field into T.
Supported targets are String, int, double, num, bool, Uri,
DateTime, and BigInt, plus their nullable forms. Anything else is a
programming error rather than a request error, so it throws instead of
rejecting.
bool accepts true, false, 1, and 0, and treats a bare flag with an
empty value as true, matching how query flags are usually written.
Integers are decimal only, and are not padded with whitespace. Dart's
parsers are lenient in two ways a request should not be: int.tryParse
reads 0x10 as 16, and every numeric parser skips surrounding whitespace,
so ?id=0x10, ?id=%2010, and ?id=10 would all name the same record.
Anything keyed on the raw text — a cache key, a rate-limit bucket, a dedup
check — then disagrees with the handler about which request this was. A
request carries a bare decimal number, so anything else is a 400.
Implementation
Result<T, Rejection> coerce<T>(String raw, {required String source}) {
Rejection bad(String type) =>
Rejection.badRequest('$source is not a valid $type');
if (T == String || T == typeOf<String?>()) {
return Ok(raw as T);
}
if (T == int || T == typeOf<int?>()) {
final value = _padded(raw) ? null : int.tryParse(raw, radix: 10);
return value == null ? Err(bad('integer')) : Ok(value as T);
}
if (T == double || T == typeOf<double?>()) {
final value = _padded(raw) ? null : double.tryParse(raw);
return value == null ? Err(bad('number')) : Ok(value as T);
}
if (T == num || T == typeOf<num?>()) {
final value = _padded(raw) ? null : num.tryParse(raw);
return value == null ? Err(bad('number')) : Ok(value as T);
}
if (T == bool || T == typeOf<bool?>()) {
final value = switch (raw.toLowerCase()) {
'true' || '1' || '' => true,
'false' || '0' => false,
_ => null,
};
return value == null ? Err(bad('boolean')) : Ok(value as T);
}
if (T == BigInt || T == typeOf<BigInt?>()) {
final value = _padded(raw) ? null : BigInt.tryParse(raw, radix: 10);
return value == null ? Err(bad('integer')) : Ok(value as T);
}
if (T == DateTime || T == typeOf<DateTime?>()) {
final value = DateTime.tryParse(raw);
return value == null ? Err(bad('date-time')) : Ok(value as T);
}
if (T == Uri || T == typeOf<Uri?>()) {
final value = Uri.tryParse(raw);
return value == null ? Err(bad('URI')) : Ok(value as T);
}
throw ArgumentError('dust_server cannot coerce a request value to $T');
}