buildOperationUri function

Uri buildOperationUri(
  1. String baseUrl,
  2. Operation operation,
  3. Map<String, Object?> params, {
  4. String pathPrefix = '',
})

The URI of one call: the path template filled from params, the declared query and then the extra query. The path replaces baseUrl's own path; pathPrefix (/api) goes before it.

Implementation

Uri buildOperationUri(String baseUrl, Operation operation, Map<String, Object?> params, {String pathPrefix = ''}) {
  var path = operation.path.replaceAllMapped(RegExp(r'\{([^}]+)\}'), (m) {
    final value = params[m.group(1)];
    return value == null || value == '' ? '' : Uri.encodeComponent('$value');
  });
  path = '$pathPrefix$path'.replaceAll(RegExp(r'/{2,}'), '/').replaceAll(RegExp(r'/+$'), '');
  final query = <String, List<String>>{};
  void add(String name, Object? value) {
    if (value == null) return;
    if (value is Iterable) {
      query[name] = value.where((v) => v != null).map((v) => _queryValue(v as Object)).toList();
    } else {
      query[name] = [_queryValue(value)];
    }
  }

  for (final name in operation.query) {
    add(name, params[name]);
  }
  // The extra query comes after the declared names and never replaces one of them.
  final extra = params[extraQueryKey];
  if (extra is Map) {
    extra.forEach((name, value) {
      final key = '$name';
      if (key.isEmpty || operation.query.contains(key) || query.containsKey(key)) return;
      add(key, value);
    });
  }
  final base = Uri.parse(baseUrl);

  return base.replace(path: path.isEmpty ? '/' : path, queryParameters: query.isEmpty ? null : query);
}