-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
[WIP] Add generator option to ignore case in pattern matching #2095
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
@googlebot I signed it! |
@@ -5,36 +5,19 @@ package(default_visibility = ["//visibility:public"]) | |||
go_library( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no idea why the bazel file changed so much...
@@ -1032,21 +1032,21 @@ func RegisterEchoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux | |||
} | |||
|
|||
var ( | |||
pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "")) | |||
pattern_EchoService_Echo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "example", "echo", "id"}, "", false)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regenerated the example gateway with the updated generator
} | ||
|
||
// New returns a new generator which generates grpc gateway files. | ||
func New(reg *descriptor.Registry, useRequestContext bool, registerFuncSuffix string, | ||
allowPatchFeature, standalone bool) gen.Generator { | ||
allowPatchFeature, standalone bool, ignoreCase bool) gen.Generator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add ignoreCase to the constructor
@@ -727,7 +727,7 @@ func (m response_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}) XXX_ResponseBody( | |||
var ( | |||
{{range $m := $svc.Methods}} | |||
{{range $b := $m.Bindings}} | |||
pattern_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}} = runtime.MustPattern(runtime.NewPattern({{$b.PathTmpl.Version}}, {{$b.PathTmpl.OpCodes | printf "%#v"}}, {{$b.PathTmpl.Pool | printf "%#v"}}, {{$b.PathTmpl.Verb | printf "%q"}})) | |||
pattern_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}} = runtime.MustPattern(runtime.NewPattern({{$b.PathTmpl.Version}}, {{$b.PathTmpl.OpCodes | printf "%#v"}}, {{$b.PathTmpl.Pool | printf "%#v"}}, {{$b.PathTmpl.Verb | printf "%q"}}, false)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for now, default to false. this is where we'll grab the option and use it to set it on each pattern
@@ -185,7 +185,7 @@ func (s *ServeMux) HandlePath(meth string, pathPattern string, h HandlerFunc) er | |||
return fmt.Errorf("parsing path pattern: %w", err) | |||
} | |||
tp := compiler.Compile() | |||
pattern, err := NewPattern(tp.Version, tp.OpCodes, tp.Pool, tp.Verb) | |||
pattern, err := NewPattern(tp.Version, tp.OpCodes, tp.Pool, tp.Verb, false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default to false in the HandlePath implementation for now. deferring to later commits or PR for this
runtime/pattern.go
Outdated
} | ||
|
||
// NewPattern returns a new Pattern from the given definition values. | ||
// "ops" is a sequence of op codes. "pool" is a constant pool. | ||
// "verb" is the verb part of the pattern. It is empty if the pattern does not have the part. | ||
// "version" must be 1 for now. | ||
// It returns an error if the given definition is invalid. | ||
func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, error) { | ||
func NewPattern(version int, ops []int, pool []string, verb string, caseSensitive bool) (Pattern, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set the caseSensitive option in the Pattern struct, so we can change the Match behavior
seems that the golangci-lint github action is not reporting where the failures occur? When I run golangci-lint --enable goimports locally, I get a bunch of weird unrelated failures :
and if I run goimports on the whole repo, many of the changes are in the generated files, and unrelated to my modification. |
So, this works as it is now. If this is ok in terms of functionality I think that would be enough. I had a quick look at implementing it as a Binding parameter, and it seems a little bit more involved, but still relatively easy. Let me know what you think. |
@@ -727,7 +731,7 @@ func (m response_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}}) XXX_ResponseBody( | |||
var ( | |||
{{range $m := $svc.Methods}} | |||
{{range $b := $m.Bindings}} | |||
pattern_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}} = runtime.MustPattern(runtime.NewPattern({{$b.PathTmpl.Version}}, {{$b.PathTmpl.OpCodes | printf "%#v"}}, {{$b.PathTmpl.Pool | printf "%#v"}}, {{$b.PathTmpl.Verb | printf "%q"}})) | |||
pattern_{{$svc.GetName}}_{{$m.GetName}}_{{$b.Index}} = runtime.MustPattern(runtime.NewPattern({{$b.PathTmpl.Version}}, {{$b.PathTmpl.OpCodes | printf "%#v"}}, {{$b.PathTmpl.Pool | printf "%#v"}}, {{$b.PathTmpl.Verb | printf "%q"}}, {{$IgnoreCase}})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in the comment, this breaks backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it defaults to false false, so the behavior is the same.
it does break runtime.NewPattern(...) signature.
I can create a separate one if that's what you mean.
runtime.NewCaseInsensitivePattern(...)?
it's a mouthful, but works for me if it works for you :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ideally, the parameters would be collapsed into an option struct, or use functional options, so that they can be modified without breaking the api in the future...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, I see what you mean with backward compatibility.
so, for minor releases, the requirement is that we can update the package without regenerating the gw?
that's very restrictive, and I would say that any func used in the generated code should be redesigned to have a functional option, or struct base parameter to reduce breaking changes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about :
type PatternOption func(*Pattern)
func WithIgnoreCase() PatternOption {
return func(h *Pattern) {
h.ignoreCase = true
}
}
NewPattern(version int, ops []int, pool []string, verb string, ...PatternOption) ) (Pattern, error) { }
that would allow the old generated code to work with the new version of the package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a valid feature so we want it. But it's an open source project on which we work after-hours and it requires different amount of time needed to spot a breaking change versus digging into a problem and finding a viable solution. I can only ask for a bit more patience :)
Let's consider a solution adding a new method:
- Code generated with version 1 and library in version 2 (with this new public method); it will work fine as the method simply won't be called.
- Code generated with version 2 and library in version 1; it will break as the generated code will contain the unknown method. But I don't think we promise such guarantees. One should always use the same or never version with regards to which was used to generate the code. @johanbrandhorst can you confirm, please?
If what I described above is correct, a solution with a new constructor like NewPatternWithOptions()
should also work. It could result in shorted generated code because options can be calculated at the top and usage would look like this: runtime.MustPattern(runtime.NewPatternWithOptions(..., patternOptions))
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adam is correct, option #2 should be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clarifying @adambabik is there any doc about backward/forward compatibility guarantees that should be observed when contributing, and to be expected when using the library?
Good that there is a path forward. I'll update the PR today.
Is there any other concern about the implementation?
documentation needed as part of the PR?
further testing I should write?
I saw that the example have some integration testing. I can change or add one to use ignore_case, and add some integration tests if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're welcome! Unfortunately I don't think there is any doc explaining that. We are trying to follow industry standards.
Is there any other concern about the implementation?
No.
documentation needed as part of the PR?
There is no separate documentation for flags so no need. The flag description should be enough.
further testing I should write?
There will be a few broken unit tests which will need to be fixed. The most important is "template_test.go". I think it can be also extended to cover this feature.
I saw that the example have some integration testing. I can change or add one to use ignore_case, and add some integration tests if needed.
An integration test would be nice. If you want to add a new protobuf file which will cover ignore_case=true
, take a look at Makefile
's proto
target to see how that can be done. Some flags have their own protobuf and *.buf.gen.yaml
files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you Adam, I had to fix a few template tests for the previous iteration, so that should be fine.
I'll look into adding a separate protobuf file to illustrate and test ignore_case.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
References to other Issues or PRs
Fixes #2091
Have you read the Contributing Guidelines?
yes
Brief description of what is fixed or changed
This adds an option to the gateway generation to ignore the url case when matching the request path.
In this first iteration, it only allows to set the option at generation time for all routes.
default to false.
Other comments