Closed juliaogris closed 2 years ago
Cam's poc generating jsonnet from protos:
package main
import (
"fmt"
"log"
"os"
"text/template"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
)
func main() {
if len(os.Args) == 1 {
log.Fatal("Missing file argument\n")
} else if len(os.Args) > 2 {
log.Fatal("Too many file arguments\n")
}
b, err := os.ReadFile(os.Args[1])
if err != nil {
log.Fatal(err)
}
fds := &descriptorpb.FileDescriptorSet{}
if err := proto.Unmarshal(b, fds); err != nil {
log.Fatal(err)
}
files, err := protodesc.NewFiles(fds)
if err != nil {
log.Fatal(err)
}
files.RangeFiles(printMethods)
}
func printMethods(fd protoreflect.FileDescriptor) bool {
sds := fd.Services()
for i := 0; i < sds.Len(); i++ {
sd := sds.Get(i)
mds := sd.Methods()
for j := 0; j < mds.Len(); j++ {
printResponseJsonnet(mds.Get(j))
}
}
return true
}
func printResponseJsonnet(md protoreflect.MethodDescriptor) {
err := tmpl.Execute(os.Stdout, md)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
var tmplStr = `
// {{.ParentFile.Package}}.{{.Parent.Name}}.{{.Name}}
function(input) {
response: {
{{- range (fields .Output.Fields) }}
{{ .JSONName }}:
{{ end -}}
},
error: null,
}
`
var tmpl = template.Must(template.New("").Funcs(map[string]interface{}{"fields": fields}).Parse(tmplStr[1:]))
func fields(flds protoreflect.FieldDescriptors) []protoreflect.FieldDescriptor {
result := make([]protoreflect.FieldDescriptor, flds.Len())
for i := 0; i < flds.Len(); i++ {
result[i] = flds.Get(i)
}
return result
}
suggested jsonnet structure:
input = {
request: ...
metadata: ...
}
output = {
response: ...
error: ...
metadata: ... ?
}
Thinking about the original pony, it could proxy to another service, doing data translation in the middle. It would be nice to be able to do this, in which case the output would need to be more flexible. For example:
output = {
respond: {
message: {...} | error: {...}
metadata: {...}
}
}
or
output = {
call: {
address: foo.com:1234
method: pkg.svc.method
input: {
message: {...}
metadata: {...}
}
}
}
Not suggesting this right away, but we should consider the output format to be able to make it possible.
pony grpc mocking would be run as:
pony servegrpc -p proto.pb [-m method_dir]
with method_dir
defaulting to .
The method dir has got a jsonnet file each for a method to be mocked as:
<pkg>.<service>.<method>.jsonnet
Well that got done quicker than expected. Thank you @camh-
Notes from brainstorming session.