docs: public String buildUrl(String path, List<Pair> queryParams, List<Pair> collectionQueryParams) {
          final StringBuilder url = new StringBuilder();
          url.append(basePath).append(path);
  
          if (queryParams != null && !queryParams.isEmpty()) {
              // support (constant) query string in `path`, e.g. "/posts?draft=1"
              String prefix = path.contains("?") ? "&" : "?";
              for (Pair param : queryParams) {
                  if (param.getValue() != null) {
                      if (prefix != null) {
                          url.append(prefix);
                          prefix = null;
                      } else {
                          url.append("&");
                      }
                      String value = parameterToString(param.getValue());
                      url.append(escapeString(param.getName())).append("=").append(escapeString(value));
                  }
              }
          }
  
          if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) {
              String prefix = url.toString().contains("?") ? "&" : "?";
              for (Pair param : collectionQueryParams) {
                  if (param.getValue() != null) {
                      if (prefix != null) {
                          url.append(prefix);
                          prefix = null;
                      } else {
                          url.append("&");
                      }
                      String value = parameterToString(param.getValue());
                      // collection query parameter value already escaped as part of parameterToPairs
                      url.append(escapeString(param.getName())).append("=").append(value);
                  }
              }
          }
  
          return url.toString();
      }