-
Notifications
You must be signed in to change notification settings - Fork 39.8k
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 protobuf binary version of OpenAPI spec #45836
Conversation
@mehdy looks like some bazel issue |
files := []fileInfo{ | ||
{".json", o.swaggerBytes, MIME_JSON}, | ||
{".pb", o.swaggerPb, MIME_PB}, | ||
{".pb.gz", o.swaggerPbGz, MIME_PB_GZ}, |
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.
Maybe we can remove this handler and use https://github.com/NYTimes/gziphandler?
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.
We would get the gzipped json for free too
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.
While I love reusing code, adding dependencies to gogep is painful and this is only 3-4 line more code here. I would like to keep it if it is not that bad.
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.
Sure!
{".json", o.swaggerBytes, MIME_JSON}, | ||
{".pb", o.swaggerPb, MIME_PB}, | ||
{".pb.gz", o.swaggerPbGz, MIME_PB_GZ}, | ||
{".json.sha512", o.swaggerHash[:], MIME_BINARY}, |
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 assume we expose the sha
for caching. Could we use a http ETag
instead? As this would make the implementation more transparent on both side? I can help with that 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.
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.
Etag
look like a good idea.
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.
ETag implemented. PTAL.
return fmt.Errorf("Serving path must ends with \".json\".") | ||
} | ||
|
||
servePathBase := servePath[:len(servePath)-5] |
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 is 5
? Is it len(".json")
?
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.
Yes, I've added a constant for ".json" and change this to len(...)
FYI:
|
} | ||
|
||
// RegisterOpenAPIService registers a handler to provides standard OpenAPI specification. | ||
// Note: servePath is the path to the filename with no extension. Supported extensions |
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.
Am I mis-reading or is that the opposite of what it actually is. servePath is the path to the filename WITH the .json extension
.
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 are right, I forgot to remove this comment after some iteration to the code. Done.
func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *openapi.Config, mux *genericmux.PathRecorderMux) (err error) { | ||
|
||
if !strings.HasSuffix(servePath, ".json") { | ||
return fmt.Errorf("Serving path must ends with \".json\".") |
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.
Why?
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.
Because OpenAPI spec is in json format. We can relax this limitation if we had a reason for it but right now it helps me remove the .json and add extensions for other formats.
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 go vet
will ask for this to become errors.New
instead of fmt.Errorf
.
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 tried go vet it didn't complain about fmt.Errorf and I guess we are doing the same in other places, I don't have strong opinion on either.
func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *openapi.Config, mux *genericmux.PathRecorderMux) (err error) { | ||
|
||
if !strings.HasSuffix(servePath, ".json") { | ||
return fmt.Errorf("Serving path must ends with \".json\".") |
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 go vet
will ask for this to become errors.New
instead of fmt.Errorf
.
func RegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *openapi.Config, mux *genericmux.PathRecorderMux) (err error) { | ||
|
||
if !strings.HasSuffix(servePath, ".json") { |
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 don't like this because it has the potential to break piping. What if my JSON information is fed in from /dev/stdin
?
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 am not sure if I understand this. The caller should specify an http serving path for the file and I am enforcing the path ends with json. It cannot be any pipe like stdin.
MIME_JSON = "application/json" | ||
MIME_PB = "application/com.github.googleapis.gnostic.OpenAPIv2+protobuf" | ||
MIME_PB_GZ = "application/x-gzip" | ||
MIME_BINARY = "application/octet-stream" |
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.
Good constants to have.
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.
Unfortunately (or fortunately) we don't need this anymore after etag implementation.
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { | ||
resp := restful.NewResponse(w) | ||
if r.URL.Path != path { | ||
resp.WriteErrorString(http.StatusNotFound, "Path not found!") |
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.
Doesn't this need to return early?
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 will and I don't think this check serve anything here, just looked at other HandleFuncs in our code and they all checked this, I will look into this more and remove this if statement if it doesn't help in any way.
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.
Oh, I didn't understand your comment earlier, yes, this needs an early return for sure. fixed.
return nil | ||
} | ||
|
||
func (o *openAPI) makeAdditionalFormats() 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.
Docstring on this would be nice. I can't figure out the purpose of this function.
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.
Good point. I like methods to be self explanatory so instead of adding comments to this, I restructure it to two toProtoBinary
and toGzip
method that is clear what they do.
@@ -187,6 +187,7 @@ func getConfig(fullMethods bool) (*openapi.Config, *restful.Container) { | |||
InfoProps: spec.InfoProps{ | |||
Title: "TestAPI", | |||
Description: "Test API", | |||
Version: "unversioned", |
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.
This doesn't look gofmt'd. (maybe a Github rendering issue?)
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.
Fixed.
protocolList []string | ||
servePath string | ||
definitions map[string]openapi.OpenAPIDefinition | ||
} | ||
|
||
func computeEtag(data []byte) string { | ||
sha := sha512.Sum512(data) | ||
return fmt.Sprintf("\"%s\"", |
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.
This looks like a good situation to either use %q
or a backtick string literal.
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.
Good point. fixed.
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 @mbohlool ! That's awesome
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { | ||
if r.URL.Path != path { | ||
w.WriteHeader(http.StatusNotFound) | ||
w.Write([]byte("Path not found!")) |
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 is indeed missing the early return
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.
Done.
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!
protocolList []string | ||
servePath string | ||
definitions map[string]openapi.OpenAPIDefinition | ||
} | ||
|
||
func computeEtag(data []byte) string { | ||
sha := sha512.Sum512(data) | ||
return fmt.Sprintf("\"%s\"", |
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 could have used fmt.Sprintf("\"%x\"", sha512.Sum512(data))
here.
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 like that. Done.
} | ||
|
||
files := []fileInfo{ | ||
{".json", o.swaggerBytes, computeEtag(o.swaggerBytes)}, |
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.
Could you compute etag in the loop? That would remove the extra field in the struct.
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.
Done.
Client side cache can be implemented using https://github.com/gregjones/httpcache/ and https://github.com/gregjones/httpcache/diskcache |
@apelisse @alexandercampbell Addressed your comments. PTAL. |
I don't see any tests for this code. Are you planning on adding some? |
@alexandercampbell To test this properly, I need some functionality from gnostic (converting proto back to json). It should be there, we can either wait for that and keep this PR open or merge this and when that is available, we can add the test. what do you think? |
@mbohlool any way to get some unit tests on some of the smaller functions in this PR? |
If unit testing is the only remaining issue, since @mbohlool is going to be out for a week, and we have 3 weeks of stabilization after feature freeze, how about we merge this and introduce the unit tests next week after he returns? |
Sure. LGTM. |
/lgtm |
Thanks for the quick changes! /lgtm |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: lavalamp, mbohlool, pwittrock
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
reapplied LGTM. test was failing because an extra file got into one of the commits (a file that I planned for next PR that is adding tests for this). I only removed that file with no other changes. |
@k8s-bot verify test this (it is not failing locally for me) |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
@k8s-bot kops aws e2e test this |
@mbohlool: The following test(s) failed:
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
Automatic merge from submit-queue |
Woot
…On May 20, 2017 11:01 AM, "Kubernetes Submit Queue" < ***@***.***> wrote:
Merged #45836 <#45836>.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#45836 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHhIAiuf7UEqkZhoUzCjfFYe3GYOzQI7ks5r7yp2gaJpZM4Nbn6G>
.
|
Fixes #45833
Partially fixes #42841