diff --git a/_examples/golang-basics/example.gen.go b/_examples/golang-basics/example.gen.go index a59409b..ea3a2ae 100644 --- a/_examples/golang-basics/example.gen.go +++ b/_examples/golang-basics/example.gen.go @@ -1,4 +1,4 @@ -// example v0.0.1 3a3a4087149f1118f0b9494fa254afab46564a1b +// example golang-basics@v0.0.1 bd2f9fc6bee7f200ba8b56fe1f287193bc5208de // -- // Code generated by webrpc-gen@v0.19.3 with ../../../gen-golang generator. DO NOT EDIT. // @@ -28,12 +28,48 @@ func WebRPCVersion() string { // Schema version of your RIDL schema func WebRPCSchemaVersion() string { - return "v0.0.1" + return "golang-basics@v0.0.1" } // Schema hash generated from your RIDL schema func WebRPCSchemaHash() string { - return "3a3a4087149f1118f0b9494fa254afab46564a1b" + return "bd2f9fc6bee7f200ba8b56fe1f287193bc5208de" +} + +type WebRPCGenVersions struct { + WebRPCGenVersion string + TmplTarget string + TmplVersion string + SchemaVersion string +} + +func WebRPCHeader() string { + return "webrpc@v0.19.3;gen-golang@unknown;golang-basics@v0.0.1" +} + +func ParseWebRPCGenVersions(header string) (*WebRPCGenVersions, error) { + versions := strings.Split(header, ";") + + if len(versions) != 3 { + return nil, fmt.Errorf("expected 3 parts while parsing webrpc header: %s", header) + } + + _, webrpcGenVersion, ok := strings.Cut(versions[0], "@") + if !ok { + return nil, fmt.Errorf("webrpc gen version could not be parsed from: %s", header) + } + + tmplTarget, tmplVersion, ok := strings.Cut(versions[1], "@") + if !ok { + return nil, fmt.Errorf("tmplTarget and tmplVersion could not be parsed from: %s", header) + } + + return &WebRPCGenVersions{ + WebRPCGenVersion: webrpcGenVersion, + TmplTarget: tmplTarget, + TmplVersion: tmplVersion, + SchemaVersion: versions[2], + }, nil } // @@ -143,9 +179,11 @@ type SearchFilter struct { } type Version struct { - WebrpcVersion string `json:"webrpcVersion"` - SchemaVersion string `json:"schemaVersion"` - SchemaHash string `json:"schemaHash"` + WebrpcVersion string `json:"webrpcVersion"` + SchemaVersion string `json:"schemaVersion"` + SchemaHash string `json:"schemaHash"` + ClientGenVersion *GenVersions `json:"clientGenVersion"` + ServerGenVersion *GenVersions `json:"serverGenVersion"` } type ComplexType struct { @@ -160,6 +198,13 @@ type ComplexType struct { User *User `json:"user"` } +type GenVersions struct { + WebRPCGenVersion string `json:"WebRPCGenVersion"` + TmplTarget string `json:"TmplTarget"` + TmplVersion string `json:"TmplVersion"` + SchemaVersion string `json:"SchemaVersion"` +} + var WebRPCServices = map[string][]string{ "ExampleService": { "Ping", @@ -231,6 +276,8 @@ func (s *exampleServiceServer) ServeHTTP(w http.ResponseWriter, r *http.Request) } }() + w.Header().Set("Webrpc", WebRPCHeader()) + ctx := r.Context() ctx = context.WithValue(ctx, HTTPResponseWriterCtxKey, w) ctx = context.WithValue(ctx, HTTPRequestCtxKey, r) @@ -658,6 +705,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType } req.Header.Set("Accept", contentType) req.Header.Set("Content-Type", contentType) + req.Header.Set("Webrpc", WebRPCHeader()) if headers, ok := HTTPRequestHeaders(ctx); ok { for k := range headers { for _, v := range headers[k] { diff --git a/_examples/golang-basics/example.ridl b/_examples/golang-basics/example.ridl index 9b9f739..c5ce2ea 100644 --- a/_examples/golang-basics/example.ridl +++ b/_examples/golang-basics/example.ridl @@ -1,8 +1,7 @@ webrpc = v1 # version of webrpc schema format (ridl or json) name = example # name of your backend app -version = v0.0.1 # version of your schema - +version = golang-basics@v0.0.1 # version of your schema # user role # which defines which type of operations user can do @@ -69,6 +68,8 @@ struct Version - webrpcVersion: string - schemaVersion: string - schemaHash: string + - clientGenVersion: GenVersions + - serverGenVersion: GenVersions struct ComplexType - meta: map @@ -81,6 +82,12 @@ struct ComplexType - mapOfUsers: map - user: User +struct GenVersions + - WebRPCGenVersion: string + - TmplTarget: string + - TmplVersion: string + - SchemaVersion: string + error 500100 MissingArgument "missing argument" error 500101 InvalidUsername "invalid username" error 400100 MemoryFull "system memory is full" diff --git a/_examples/golang-basics/example_test.go b/_examples/golang-basics/example_test.go index 1da0f52..7340a19 100644 --- a/_examples/golang-basics/example_test.go +++ b/_examples/golang-basics/example_test.go @@ -38,6 +38,14 @@ func TestStatus(t *testing.T) { assert.NoError(t, err) } +func TestVersion(t *testing.T) { + version, err := client.Version(context.Background()) + + assert.NoError(t, err) + assert.NotNil(t, version.ClientGenVersion) + assert.NotNil(t, version.ServerGenVersion) +} + func TestGetUser(t *testing.T) { { arg1 := map[string]string{"a": "1"} diff --git a/_examples/golang-basics/golang-basics b/_examples/golang-basics/golang-basics new file mode 100755 index 0000000..147d437 Binary files /dev/null and b/_examples/golang-basics/golang-basics differ diff --git a/_examples/golang-basics/main.go b/_examples/golang-basics/main.go index 61b5a50..bf2b564 100644 --- a/_examples/golang-basics/main.go +++ b/_examples/golang-basics/main.go @@ -48,10 +48,44 @@ func (rpc *ExampleServiceRPC) Status(ctx context.Context) (bool, error) { } func (rpc *ExampleServiceRPC) Version(ctx context.Context) (*Version, error) { + req := RequestFromContext(ctx) + writer := ResponseWriterFromContext(ctx) + + if writer.Header().Get("Webrpc") == "" { + return nil, fmt.Errorf("server webrpc header is missing") + } + + serverVersions, err := ParseWebRPCGenVersions(writer.Header().Get("Webrpc")) + if err != nil { + return nil, fmt.Errorf("parse server webrpc gen versions: %w", err) + } + + var clientVersions *GenVersions + if req.Header.Get("Webrpc") != "" { + parsedVersions, err := ParseWebRPCGenVersions(req.Header.Get("Webrpc")) + if err != nil { + return nil, fmt.Errorf("parse client webrpc gen versions: %w", err) + } + + clientVersions = &GenVersions{ + WebRPCGenVersion: parsedVersions.WebRPCGenVersion, + TmplTarget: parsedVersions.TmplTarget, + TmplVersion: parsedVersions.TmplVersion, + SchemaVersion: parsedVersions.SchemaVersion, + } + } + return &Version{ - WebrpcVersion: WebRPCVersion(), - SchemaVersion: WebRPCSchemaVersion(), - SchemaHash: WebRPCSchemaHash(), + WebrpcVersion: WebRPCVersion(), + SchemaVersion: WebRPCSchemaVersion(), + SchemaHash: WebRPCSchemaHash(), + ClientGenVersion: clientVersions, + ServerGenVersion: &GenVersions{ + WebRPCGenVersion: serverVersions.WebRPCGenVersion, + TmplTarget: serverVersions.TmplTarget, + TmplVersion: serverVersions.TmplVersion, + SchemaVersion: serverVersions.SchemaVersion, + }, }, nil } diff --git a/_examples/golang-imports/api.gen.go b/_examples/golang-imports/api.gen.go index e454f74..98adb91 100644 --- a/_examples/golang-imports/api.gen.go +++ b/_examples/golang-imports/api.gen.go @@ -33,6 +33,42 @@ func WebRPCSchemaHash() string { return "eb9a5d4082a36a8cb84eaa4b3e1091fc4f1f6f3d" } +type WebRPCGenVersions struct { + WebRPCGenVersion string + TmplTarget string + TmplVersion string + SchemaVersion string +} + +func WebRPCHeader() string { + return "webrpc@v0.19.3;gen-golang@unknown;v1.0.0" +} + +func ParseWebRPCGenVersions(header string) (*WebRPCGenVersions, error) { + versions := strings.Split(header, ";") + + if len(versions) != 3 { + return nil, fmt.Errorf("expected 3 parts while parsing webrpc header: %s", header) + } + + _, webrpcGenVersion, ok := strings.Cut(versions[0], "@") + if !ok { + return nil, fmt.Errorf("webrpc gen version could not be parsed from: %s", header) + } + + tmplTarget, tmplVersion, ok := strings.Cut(versions[1], "@") + if !ok { + return nil, fmt.Errorf("tmplTarget and tmplVersion could not be parsed from: %s", header) + } + + return &WebRPCGenVersions{ + WebRPCGenVersion: webrpcGenVersion, + TmplTarget: tmplTarget, + TmplVersion: tmplVersion, + SchemaVersion: versions[2], + }, nil +} + // // Common types // @@ -146,6 +182,8 @@ func (s *exampleAPIServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { } }() + w.Header().Set("Webrpc", WebRPCHeader()) + ctx := r.Context() ctx = context.WithValue(ctx, HTTPResponseWriterCtxKey, w) ctx = context.WithValue(ctx, HTTPRequestCtxKey, r) @@ -399,6 +437,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType } req.Header.Set("Accept", contentType) req.Header.Set("Content-Type", contentType) + req.Header.Set("Webrpc", WebRPCHeader()) if headers, ok := HTTPRequestHeaders(ctx); ok { for k := range headers { for _, v := range headers[k] { diff --git a/client.go.tmpl b/client.go.tmpl index 23f14d9..39eff09 100644 --- a/client.go.tmpl +++ b/client.go.tmpl @@ -208,6 +208,7 @@ func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType } req.Header.Set("Accept", contentType) req.Header.Set("Content-Type", contentType) + req.Header.Set("Webrpc", WebRPCHeader()) if headers, ok := HTTPRequestHeaders(ctx); ok { for k := range headers { for _, v := range headers[k] { diff --git a/main.go.tmpl b/main.go.tmpl index e298dd4..7185152 100644 --- a/main.go.tmpl +++ b/main.go.tmpl @@ -96,6 +96,44 @@ func WebRPCSchemaHash() string { return "{{.SchemaHash}}" } +type WebRPCGenVersions struct { + WebRPCGenVersion string + TmplTarget string + TmplVersion string + SchemaVersion string +} + +// WebRPCHeader +// TmplVersion might be empty when generated from local template folder +func WebRPCHeader() string { + return "webrpc@{{.WebrpcGenVersion}};{{.TmplTarget}}@{{ if eq .TmplVersion "" }}unknown{{ else }}{{.TmplVersion}}{{end}};{{.SchemaVersion}}" +} + +func ParseWebRPCGenVersions(header string) (*WebRPCGenVersions, error) { + versions := strings.Split(header, ";") + + if len(versions) != 3 { + return nil, fmt.Errorf("expected 3 parts while parsing webrpc header: %s", header) + } + + _, webrpcGenVersion, ok := strings.Cut(versions[0], "@") + if !ok { + return nil, fmt.Errorf("webrpc gen version could not be parsed from: %s", header) + } + + tmplTarget, tmplVersion, ok := strings.Cut(versions[1], "@") + if !ok { + return nil, fmt.Errorf("tmplTarget and tmplVersion could not be parsed from: %s", header) + } + + return &WebRPCGenVersions{ + WebRPCGenVersion: webrpcGenVersion, + TmplTarget: tmplTarget, + TmplVersion: tmplVersion, + SchemaVersion: versions[2], + }, nil +} + {{- printf "\n" -}} {{- if eq $opts.importTypesFrom "" }} diff --git a/server.go.tmpl b/server.go.tmpl index 67dc7f3..6fc3588 100644 --- a/server.go.tmpl +++ b/server.go.tmpl @@ -37,6 +37,8 @@ func (s *{{$serviceName}}) ServeHTTP(w http.ResponseWriter, r *http.Request) { } }() + w.Header().Set("Webrpc", WebRPCHeader()) + ctx := r.Context() ctx = context.WithValue(ctx, HTTPResponseWriterCtxKey, w) ctx = context.WithValue(ctx, HTTPRequestCtxKey, r)