-
-
Notifications
You must be signed in to change notification settings - Fork 444
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
Parse parameters in URL at validation time #149
Parse parameters in URL at validation time #149
Conversation
There may have some parameters define in 'url' of servers definition and those parameter names will be need to store parameter values. In current implementation we will parse 'url' to get parameters name for each incoming request, now change to parse parameters in 'url' at spec definition validation time and store results to avoid parse it for each incoming request.
This sounds like you want memoization. How about just defining a private map that serves as a cache for calls to Is this for optimization reasons or is this about validating spec data before actually needing the spec to be valid? In the case of the latter I think the parsing/check should just be added to |
This is for optimization reason. The purpose is to reduce cost during request validation. My first idea is also add a private map to cache previous calculated results, but map operation also more expensive than a local variable for each server:
Benchmark codes as below: var pmap map[string][]string = make(map[string][]string)
func (server Server) ParameterNames() ([]string, error) {
pattern := server.URL
if v, ok := pmap[pattern]; ok {
return v, nil
}
var params []string
for len(pattern) > 0 {
i := strings.IndexByte(pattern, '{')
if i < 0 {
break
}
pattern = pattern[i+1:]
i = strings.IndexByte(pattern, '}')
if i < 0 {
return nil, errors.New("Missing '}'")
}
params = append(params, strings.TrimSpace(pattern[:i]))
pattern = pattern[i+1:]
}
pmap[server.URL] = params
return params, nil
}
func (server Server) ParameterNames2() ([]string, error) {
pattern := server.URL
var params []string
for len(pattern) > 0 {
i := strings.IndexByte(pattern, '{')
if i < 0 {
break
}
pattern = pattern[i+1:]
i = strings.IndexByte(pattern, '}')
if i < 0 {
return nil, errors.New("Missing '}'")
}
params = append(params, strings.TrimSpace(pattern[:i]))
pattern = pattern[i+1:]
}
return params, nil
}
func BenchmarkServerParamNames_WithPrivateMapCache(t *testing.B) {
server := &openapi3.Server{
URL: "http://{x}.{y}.example.com",
}
server.ParameterNames()
t.ResetTimer()
for i := 0; i < t.N; i++ {
p, _ := server.ParameterNames()
if len(p) != 2 {
panic("error")
}
}
}
func BenchmarkServerParamNames_CalculateEachTime(t *testing.B) {
server := &openapi3.Server{
URL: "http://{x}.{y}.example.com",
}
t.ResetTimer()
for i := 0; i < t.N; i++ {
p, _ := server.ParameterNames2()
if len(p) != 2 {
panic("error")
}
}
}
func BenchmarkServerParamNames_LocalVariable(t *testing.B) {
server := &openapi3.Server{
URL: "http://{x}.{y}.example.com",
VariabesInURL: []string{"x", "y"},
}
t.ResetTimer()
for i := 0; i < t.N; i++ {
p := server.VariabesInURL
if len(p) != 2 {
panic("error")
}
}
} |
Let's keep the code simple & API straightforward: let's just do a private map. |
Yes, this is not the most expensive operation, but this cost can be reduced very easy by introduce a local variable. |
If you're still up for it I suggest you tune performance in the legacyrouter itself once #210 is merged. |
There may have some parameters define in 'url' of servers definition
and those parameter names will be need to store parameter values. In
current implementation we will parse 'url' to get parameters name for
each incoming request, now change to parse parameters in 'url' at spec
definition validation time and store results to avoid parse it for
each incoming request.