Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add URL wildcard feature (fixes #47) #53

Merged
merged 40 commits into from
Jul 20, 2023
Merged

Conversation

jmileham
Copy link
Member

/domain @samandmoore @Betterment/webvalve-core
/platform @samandmoore @Betterment/webvalve-core

Regexp felt too powerful and would've been a major breaking change, so here's an attempt to sneak in wildcard * support without changing the syntax too much. I'll call out some interesting bits in comments.

Copy link
Member Author

@jmileham jmileham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are my notes!

spec/webvalve/manager_spec.rb Show resolved Hide resolved
spec/webvalve/service_url_converter_spec.rb Show resolved Hide resolved
spec/webvalve/service_url_converter_spec.rb Show resolved Hide resolved
spec/webvalve/service_url_converter_spec.rb Show resolved Hide resolved
spec/webvalve/service_url_converter_spec.rb Show resolved Hide resolved
spec/webvalve/manager_spec.rb Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
README.md Outdated
@@ -218,6 +218,28 @@ WebValve.register FakeBank, url: ENV.fetch("SOME_CUSTOM_API_URL")
WebValve.register FakeBank, url: "https://some-service.com"
```

## Mocking dynamic URLs with wildcards
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mocking is probably not the right word - what is?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might just say "Using wildcards for dynamic URLs"

@jmileham
Copy link
Member Author

jmileham commented Jul 13, 2023

Barring additional feedback on my newer changes, I think the major outstanding question is whether we're comfy with the level of grossness that the suffix pattern adds to every single URL pattern in webmock. How bad is it that http://foo.co will also match requests to http://foo.com if we don't add it? I can imagine it being very annoying for some kind of app integrating hundreds of services, like an API aggregator of some kind, but it's probably mostly not going to have security repercussions?

@jmileham
Copy link
Member Author

mostly correctness repercussions, though, and if you have a couple similar domains/apps it could really mess you up until you figure out what's going on.

@jmileham
Copy link
Member Author

Maybe it happens more around path suffixes honestly if you're treating a bunch of subtrees of an app as different webmock domains.

@jmileham
Copy link
Member Author

Another sub-consideration: if we decide to keep the suffix pattern, since it's a breaking change that somebody might have been taking advantage of (e.g. including the static part of a dynamic token at the end of the URL) is it worth putting a fail-safe change management feature in there, e.g. encoding a WebValve.strict_suffix_matching = true into the generated config and falling back to the non-strict suffix matching? Or is the current behavior better understood as a bug?

Relatedly, you could make the case that the wildcard pattern is a breaking change worthy of a similar fail-safe upgrade pattern because you used to be able to use the * literal in your URLs and now it's a metacharacter unless you escape it both in the webvalve config, and probably in app use. I think that's vanishingly unlikely and not worth doing, but just calling it out.

@jmileham
Copy link
Member Author

I took a stab at a post_install_message that discloses both behavior changes and bumped version to 2.0 because of the breaking changes.

@jmileham
Copy link
Member Author

If we wanted to go in an entirely different direction we could pursue Addressable templates instead, which would probably look cleaner and have some of the safety I had to engineer into this by default. Addressable templates (mostly? completely?) wrap their dynamic sections in curlies which are relatively unlikely to be present unencoded in URLs.

@jmileham
Copy link
Member Author

Notably with URL templates we'd either have to suffix user-provided URL templates dynamically to enable them to support arbitrary suffixes, or people would have to provide their own suffixes. Could get finicky. The UX of wildcarding is probably easier to understand for somebody who doesn't slice and dice URLs at a framework level for a living.

@jmileham
Copy link
Member Author

Oh maybe middle ground: use wildcard syntax but render as addressable templates? Might be quite a bit fancier on the inside because the template representation of * would likely change by context, but that might be doable, and the resulting template is probably more legible than a hairy regexp.

lib/webvalve/version.rb Outdated Show resolved Hide resolved
@samandmoore
Copy link
Member

Barring additional feedback on my newer changes, I think the major outstanding question is whether we're comfy with the level of grossness that the suffix pattern adds to every single URL pattern in webmock. How bad is it that http://foo.co will also match requests to http://foo.com if we don't add it? I can imagine it being very annoying for some kind of app integrating hundreds of services, like an API aggregator of some kind, but it's probably mostly not going to have security repercussions?

I'm fine with being more restrictive. I think that adding the trailing * is a relatively easy fix for anyone in that situation.

@samandmoore
Copy link
Member

Another sub-consideration: if we decide to keep the suffix pattern, since it's a breaking change that somebody might have been taking advantage of (e.g. including the static part of a dynamic token at the end of the URL) is it worth putting a fail-safe change management feature in there, e.g. encoding a WebValve.strict_suffix_matching = true into the generated config and falling back to the non-strict suffix matching? Or is the current behavior better understood as a bug?

I consider the behavior a bug. Given that there will be a way to restore the behavior, I'm fine with making the breaking changes and doing a major version bump.

Relatedly, you could make the case that the wildcard pattern is a breaking change worthy of a similar fail-safe upgrade pattern because you used to be able to use the * literal in your URLs and now it's a metacharacter unless you escape it both in the webvalve config, and probably in app use. I think that's vanishingly unlikely and not worth doing, but just calling it out.

Agreed

lib/webvalve/service_url_converter.rb Outdated Show resolved Hide resolved
@@ -2,48 +2,76 @@
require 'addressable/template'

module WebValve
# @api private
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this reminds me, i gotta do a pass over this library to call private_constants. will make a note for myself for that too

spec/webvalve/service_url_converter_spec.rb Outdated Show resolved Hide resolved
Copy link
Member

@samandmoore samandmoore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

domainlgtm platformlgtm

@jmileham
Copy link
Member Author

jmileham commented Jul 18, 2023

@ABaldwinHunter since you proposed issue #47 and @slondr since you upvoted, does this feature scratch the itch you're looking to scratch? We're ready to pull the trigger on it but want to do a final check that we didn't build the wrong thing. :) See the README diff for the TL;DR.

samandmoore and others added 2 commits July 18, 2023 11:04
* origin/main:
  Bump webvalve to 1.3.0
  Drop support for older rails and rubies (#54)
Copy link
Member

@samandmoore samandmoore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

domainlgtm

@jmileham
Copy link
Member Author

Addressable::Templates turn out to be too strict in practice to be a general purpose URL matcher for Webvalve. URLs like http://foo.com/?bar don't match http://foo.com/{?query*} because there's no = in the query param. URLs like http://foo.com/?bar=baz,bump don't match because , is a reserved character in the RFCs despite it being commonly used on the wire. So I'm going to revert some commits here to get back to the Regexp strategy, which will result in less legible URL patterns in webmock, but we'll live.

@jmileham
Copy link
Member Author

Ok, this PR, back in Regexp-backed form works with one of our largest codebases. @ABaldwinHunter @slondr please hit us with feedback but the fact that in spite of the slight behavior changes it didn't break a big app that heavily uses webvalve also gives me confidence that this is not a one way door.

Copy link
Member

@samandmoore samandmoore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

domainlgtm platformlgtm

Copy link
Member

@samandmoore samandmoore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

domainlgtm platformlgtm

@samandmoore samandmoore merged commit d8668c5 into main Jul 20, 2023
10 checks passed
@samandmoore samandmoore deleted the jmileham/url_wildcards branch July 20, 2023 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants