GuidWildcardMatcher to match on GUIDs #387

Closed
opened 2025-12-29 08:27:15 +01:00 by adam · 14 comments
Owner

Originally created by @brogdogg on GitHub (Nov 17, 2021).

Is your feature request related to a problem? Please describe.

I have been using the RegexMatcher to do matches for paths with GUIDs, but after a while the Pattern in the JSON mappings becomes unwieldly long in length when a few GUIDs are used.

Describe the solution you'd like

Would like a matcher to allow for matching a GUID (mostly in the Path). For example:

  • Path - http://localhost/v1.0/4a7eaad5-bbe7-4579-bb0b-7c85352fe1b6/task/edef5b4a-33bb-4920-bb42-1d5e6283984e

  • JSON mapping:

    {
        "Request" : 
        {
          "Path": {
            "Matchers": [{
              "Name": "GuidWildcardMatcher",
              "Pattern": "/*/{D}/task/{D}",
              "IgnoreCase": true
            }]
          }
        }
    }
    

Where the tokens used in the pattern match up with the GUID.ToString(string? format) method as described here.

Describe alternatives you've considered

None - I can use the RegexMatcher if the feature is not accepted.

Is your feature request supported by WireMock (java version)? Please provide details.

I do not believe this is supported in the java version (I did a search and couldn't find anything that I could see)

Originally created by @brogdogg on GitHub (Nov 17, 2021). **Is your feature request related to a problem? Please describe.** I have been using the `RegexMatcher` to do matches for paths with GUIDs, but after a while the `Pattern` in the JSON mappings becomes unwieldly long in length when a few GUIDs are used. **Describe the solution you'd like** Would like a matcher to allow for matching a GUID (mostly in the `Path`). For example: - `Path` - `http://localhost/v1.0/4a7eaad5-bbe7-4579-bb0b-7c85352fe1b6/task/edef5b4a-33bb-4920-bb42-1d5e6283984e` - JSON mapping: ```JSON { "Request" : { "Path": { "Matchers": [{ "Name": "GuidWildcardMatcher", "Pattern": "/*/{D}/task/{D}", "IgnoreCase": true }] } } } ``` Where the tokens used in the pattern match up with the `GUID.ToString(string? format)` method as described [here](https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=net-5.0#System_Guid_ToString_System_String_). **Describe alternatives you've considered** None - I can use the `RegexMatcher` if the feature is not accepted. **Is your feature request supported by [WireMock (java version)](https://www.wiremock.org)? Please provide details.** I do not believe this is supported in the java version (I did a search and couldn't find anything that I could see)
adam added the feature label 2025-12-29 08:27:15 +01:00
adam closed this issue 2025-12-29 08:27:15 +01:00
Author
Owner

@StefH commented on GitHub (Nov 17, 2021):

It would also be an option to update the wildcard matcher.
Currently the wildcard matcher supports a *. Maybe when adding logic to understand also GUID(D) could be an option...

Just thinking....

@StefH commented on GitHub (Nov 17, 2021): It would also be an option to update the wildcard matcher. Currently the wildcard matcher supports a `*`. Maybe when adding logic to understand also `GUID(D)` could be an option... Just thinking....
Author
Owner

@brogdogg commented on GitHub (Nov 17, 2021):

True, I mean could it be a more general matcher available in JSON as well? I forked and trying to play with it to see.

@brogdogg commented on GitHub (Nov 17, 2021): True, I mean could it be a more general matcher available in JSON as well? I forked and trying to play with it to see.
Author
Owner

@brogdogg commented on GitHub (Nov 17, 2021):

OK, after playing I see what you mean by updating the wildcard matcher, since it extends RegexMatcher. I was trying something like this:

            return patterns.Select(pattern => new AnyOf<string, StringPattern>(
                new StringPattern
                {
                    Pattern = "^" + Regex.Escape(pattern.GetPattern())
                                         .Replace(@"\{GUIDD}", "([A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12})")
                                         .Replace(@"\{GUIDN}", "([A-Z0-9]{32})")
                                         .Replace(@"\{GUIDP}", @"(\([A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12}\))")
                                         .Replace(@"\*",".*")
                                         .Replace(@"\?", ".")
                            + "$",
                    PatternAsFile = pattern.IsSecond ? pattern.Second.PatternAsFile : null
                }))
                .ToArray();

and was able to get things working.

My only thought about putting it in the WildcardMatcher is I would not think to look there for a GUID matcher. But I'm honestly having a difficult time thinking of a better solution. Creating a new GuidMatcher and extending RegexMatcher is where I first went, which would work but it ain't immediately clear you have full Regex capabilities on the matcher.

Anyways, thanks for the consideration.

@brogdogg commented on GitHub (Nov 17, 2021): OK, after playing I see what you mean by updating the wildcard matcher, since it extends `RegexMatcher`. I was trying something like this: ```c# return patterns.Select(pattern => new AnyOf<string, StringPattern>( new StringPattern { Pattern = "^" + Regex.Escape(pattern.GetPattern()) .Replace(@"\{GUIDD}", "([A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12})") .Replace(@"\{GUIDN}", "([A-Z0-9]{32})") .Replace(@"\{GUIDP}", @"(\([A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12}\))") .Replace(@"\*",".*") .Replace(@"\?", ".") + "$", PatternAsFile = pattern.IsSecond ? pattern.Second.PatternAsFile : null })) .ToArray(); ``` and was able to get things working. My only thought about putting it in the `WildcardMatcher` is I would not think to look there for a GUID matcher. But I'm honestly having a difficult time thinking of a better solution. Creating a new `GuidMatcher` and extending `RegexMatcher` is where I first went, which would work but it ain't immediately clear you have full `Regex` capabilities on the matcher. Anyways, thanks for the consideration.
Author
Owner

@StefH commented on GitHub (Nov 17, 2021):

What we also could do is 'extending' the RegEx specification by adding GUID, GUIDN or GUIDP.

So like \d matches a digit, the \GUID should match a Guid.

So maybe new logic should be moved to a separate helper NuGet / project / class and then replace all logic in WireMock.Net which uses Regex, by this new "RegexExtended".

?

@StefH commented on GitHub (Nov 17, 2021): What we also could do is 'extending' the RegEx specification by adding GUID, GUIDN or GUIDP. So like `\d` matches a digit, the `\GUID` should match a Guid. So maybe new logic should be moved to a separate helper NuGet / project / class and then replace all logic in WireMock.Net which uses Regex, by this new "RegexExtended". ?
Author
Owner

@brogdogg commented on GitHub (Nov 18, 2021):

I like the idea. I took a look at the RegexParser. ScanBackslash method and it is quite involved and isn't really built for extensibility, which would result in divergent code paths. So doesn't feel like a longterm solution? Unless could be added to the main library.

Anyways, if it were to be done maybe something similar to the \p{}, could do something like \g{} ( \G is already used).

@brogdogg commented on GitHub (Nov 18, 2021): I like the idea. I took a look at the [RegexParser. ScanBackslash](https://github.com/dotnet/runtime/blob/f6e2377da05888fda0fda18ee0959683e830d8d9/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs#L1156) method and it is quite involved and isn't really built for extensibility, which would result in divergent code paths. So doesn't feel like a longterm solution? Unless could be added to the main library. Anyways, if it were to be done maybe something similar to the `\p{}`, could do something like `\g{}` ( `\G` is already used).
Author
Owner

@StefH commented on GitHub (Nov 18, 2021):

I just meant that we don't need to write parser code, just use your replace logic, like:

void Main()
{
	var pattern = @"\d \GUID";
	
	var r = new Regex2(pattern, RegexOptions.Compiled);
	r.Matches("1 baf04077-a3c0-454b-ac6f-9fec00b8e170").Dump();
}

public class Regex2 : Regex
{
	public Regex2(string pattern, RegexOptions options) : base(Replace(pattern), options)
	{
	}
	
	private static string Replace(string pattern)
	{
		return pattern.Replace(@"\GUID", @"[0-9A-Fa-f\-]{36}");
	}
}

image

@StefH commented on GitHub (Nov 18, 2021): I just meant that we don't need to write parser code, just use your replace logic, like: ``` csharp void Main() { var pattern = @"\d \GUID"; var r = new Regex2(pattern, RegexOptions.Compiled); r.Matches("1 baf04077-a3c0-454b-ac6f-9fec00b8e170").Dump(); } public class Regex2 : Regex { public Regex2(string pattern, RegexOptions options) : base(Replace(pattern), options) { } private static string Replace(string pattern) { return pattern.Replace(@"\GUID", @"[0-9A-Fa-f\-]{36}"); } } ``` ![image](https://user-images.githubusercontent.com/249938/142425176-8f0ecaa3-db46-45a7-9b4b-c31f8895d4a8.png)
Author
Owner

@brogdogg commented on GitHub (Nov 18, 2021):

I see what you mean.

@brogdogg commented on GitHub (Nov 18, 2021): I see what you mean.
Author
Owner

@brogdogg commented on GitHub (Nov 18, 2021):

OK, I got a library where I have most of the work done. Will try to package into a nuget later and publish.

@brogdogg commented on GitHub (Nov 18, 2021): OK, I got a library where I have most of the work done. Will try to package into a nuget later and publish.
Author
Owner

@StefH commented on GitHub (Nov 18, 2021):

Cool.

However, if it's only a single class file, maybe it's better to just include it in this project first.

@StefH commented on GitHub (Nov 18, 2021): Cool. However, if it's only a single class file, maybe it's better to just include it in this project first.
Author
Owner

@brogdogg commented on GitHub (Nov 18, 2021):

Meh... it could be useful for others too I suppose.

@brogdogg commented on GitHub (Nov 18, 2021): Meh... it could be useful for others too I suppose.
Author
Owner

@brogdogg commented on GitHub (Nov 18, 2021):

I could try to integrate it on my fork as a single class integrated and put up a PR. Would that be helpful?

@brogdogg commented on GitHub (Nov 18, 2021): I could try to integrate it on my fork as a single class integrated and put up a PR. Would that be helpful?
Author
Owner

@StefH commented on GitHub (Nov 28, 2021):

Hello @brogdogg;

Did you achieve any progress on this?

@StefH commented on GitHub (Nov 28, 2021): Hello @brogdogg; Did you achieve any progress on this?
Author
Owner

@brogdogg commented on GitHub (Nov 29, 2021):

@StefH I had it done and then realized my line endings got jacked... and then Thanksgiving happened, so took a break. Will try to figure out my line endings and get it ready.

@brogdogg commented on GitHub (Nov 29, 2021): @StefH I had it done and then realized my line endings got jacked... and then Thanksgiving happened, so took a break. Will try to figure out my line endings and get it ready.
Author
Owner

@brogdogg commented on GitHub (Dec 13, 2021):

Thanks @StefH , I was able to pull the latest version and use this feature. Thanks again for being so open to my feature suggestion.

@brogdogg commented on GitHub (Dec 13, 2021): Thanks @StefH , I was able to pull the latest version and use this feature. Thanks again for being so open to my feature suggestion.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net#387