foss42 / apidash

API Dash is a beautiful open-source cross-platform API Client built using Flutter which can help you easily create & customize your API requests, visually inspect responses and generate API integration code. A lightweight alternative to postman/insomnia.
https://apidash.dev
Apache License 2.0
1.37k stars 257 forks source link

Fuzzy header search #380

Closed PratyushChauhan closed 2 weeks ago

PratyushChauhan commented 3 months ago

PR Description

Previously we were only checking if a pattern is present in a header string. As a result you would not get suggestions if you made a typo. BEFORE: 320200891-35e13df0-5a8a-49bd-adf9-a96b5e22d569

This PR attempts to fix this issue using Fuzzy package.

AFTER: 320200720-079a90ca-80e6-41fe-ad90-6e37702410bb

Related Issues

Checklist

Added/updated tests?

All previous tests except one have been added for the new function.

animator commented 3 months ago

It should show recommendation if there is a typo but if an exact substring match exists, it should show only them.

PratyushChauhan commented 3 months ago

It should show recommendation if there is a typo but if an exact substring match exists, it should show only them.

@animator I have a suggestion to implement this.

in getFuzzyHeaderSuggestions():

List<String> getFuzzyHeaderSuggestions(String pattern) {
  final keys = headers.keys.toList();
  final fuse = Fuzzy(keys,
      options: FuzzyOptions(
        distance: 10,
        tokenize: true,
        matchAllTokens: true,
        tokenSeparator: "-",
        threshold: 0.2,
        shouldSort: true,
        minMatchCharLength: 1,
      ));
  final results = fuse.search(pattern);
  final List<String> suggestions =
      results.map((result) => result.item as String).toList();
  return suggestions;
}

when we obtain suggestions we can then iteratively sort them into 2 lists, "predictions" and "recommendations" {in case there is a typo}.

Example: every suggestion that exactly contains(pattern) will be a "prediction", else it will go to "recommendations". Then if predictions.length == 0 in which case the user made a typo, we will display the fuzzy "recommendations" list otherwise we will only display "predictions" that will contain the pattern substring.

Let me know if this is desirable.

PratyushChauhan commented 3 months ago

Doing this also passes the one test case I had to edit. This should do better than the previous approach.

PratyushChauhan commented 3 months ago

Passes all test cases and does not show approximate suggestions if no typo exists. If typo exists then it shows fuzzy suggestions.

ashitaprasad commented 3 months ago

@PratyushChauhan For the case, when the user just types a the result should include headers beginning with a followed by other headers. This is not happening currently.

Screenshot 2024-04-11 at 8 05 32 AM
PratyushChauhan commented 3 months ago

@ashitaprasad worked on your suggestion, now the first character match is given preference in predictions.

image

animator commented 3 months ago

@PratyushChauhan Why is Accept lower than Accept-Charset in your implementation?

PratyushChauhan commented 3 months ago

@animator this most likely happens when we re-order the predictions {in case of typo} to include first character matching strings near the top.

// sort the predictions based on first character match
  for (int i = 0; i < predictions.length; i++) {
    if (predictions[i][0].toLowerCase() == pattern[0].toLowerCase()) {
      final String temp = predictions.removeAt(i);
      predictions.insert(0, temp); //push to front
    }
  }

In case of a typo each string that has a matching first character is pushed to position 0. Hence the order given by the fuzzy finder is reversed which makes Accept have a lower ranking than Accept-Charset.

A way to fix this would be to introduce a currentIndex variable to keep track of which index we need to push to. This will preserve the order given by the fuzzy finder package.

Fix:

  int currentIndex = 0;
  // sort the predictions based on first character match
  for (int i = 0; i < predictions.length; i++) {
    if (predictions[i][0].toLowerCase() == pattern[0].toLowerCase()) {
      final String temp = predictions.removeAt(i);
      predictions.insert(currentIndex, temp); //push to front
      currentIndex++;
    }
  }

image

PratyushChauhan commented 2 months ago

@animator @ashitaprasad is this implementation fine?