Skip to content

Commit

Permalink
output method hash instead of parsing live
Browse files Browse the repository at this point in the history
  • Loading branch information
dorner committed Mar 3, 2024
1 parent 1a33287 commit 9a096f2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 12 deletions.
21 changes: 13 additions & 8 deletions lib/grpc_rest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ def sub_field(proto, name)
return existing if existing

descriptor = proto.class.descriptor.to_a.find { |a| a.name == name }
return nil if descriptor.nil?

klass = descriptor.submsg_name.split('.').map(&:camelize).join('::').constantize
sub_record = klass.new
proto.public_send(:"#{name}=", sub_record)
Expand All @@ -18,23 +20,26 @@ def assign_value(proto, path, value)
tokens = path.split('.')
tokens[0...-1].each do |path_seg|
proto = sub_field(proto, path_seg)
return if proto.nil?
end
proto.public_send(:"#{tokens.last}=", value)
proto.public_send(:"#{tokens.last}=", value) if proto.respond_to?(:"#{tokens.last}=")
end

def assign_params(request, param_string, body_string, params)
def assign_params(request, param_hash, body_string, params)
parameters = params.to_h.deep_dup
# each instance of {variable} means that we set the corresponding param variable into the
# Protobuf request
# The variable pattern could have dots which indicate we need to drill into the request
# to set it - e.g. {subrecord.foo} means we need to set the value of `request.subrecord.foo` to `params[:foo].`
# We can also do simple wildcard replacement if there's a * - for example, {name=something-*}
# means we should set `request.name` to "something-#{params[:name]}".
param_string.scan(/\{(.*?)}/).each do |match|
name, val = match[0].split('=')
val = '*' if val.blank?
name_tokens = name.split('.')
assign_value(request, name, val.gsub('*', parameters.delete(name_tokens.last)))
param_hash.each do |entry|
name_tokens = entry[:split_name]
value_to_use = parameters.delete(name_tokens.last)
if entry[:val]
value_to_use = value_to_use.gsub('*', entry[:val])
end
assign_value(request, entry[:name], value_to_use)
end
if body_string.present? && body_string != '*'
# we need to "splat" the body parameters into the given sub-record rather than into the top-level.
Expand All @@ -45,7 +50,7 @@ def assign_params(request, param_string, body_string, params)
end

# assign remaining parameters
parameters.except('action', 'controller').each do |k, v|
parameters.each do |k, v|
assign_value(request, k, v)
end
end
Expand Down
21 changes: 18 additions & 3 deletions protoc-gen-rails/internal/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type method struct {
Name string
RequestType string
Path string
PathInfo []PathInfo
Body string
HttpMethod string
}
Expand All @@ -47,11 +48,20 @@ class {{.ControllerName}}Controller < ActionController::Base
rescue_from Google::Protobuf::TypeError do |e|
render json: GrpcRest.error_msg(e)
end
METHOD_PARAM_MAP = {
{{range .Methods }}
"{{.Name}}" => [
{{range .PathInfo -}}
{name: "{{.Name}}", val: {{if .HasValPattern}}"{{.ValPattern}}"{{else}}nil{{end}}, split_name:{{.SplitName}}},
{{end -}}
],
{{end -}}
}.freeze
{{$fullServiceName := .FullServiceName -}}
{{range .Methods }}
def {{.Name}}
grpc_request = {{.RequestType}}.new
GrpcRest.assign_params(grpc_request, "{{.Path}}", "{{.Body}}", request.parameters)
GrpcRest.assign_params(grpc_request, METHOD_PARAM_MAP["{{.Name}}"], "{{.Body}}", request.parameters)
render json: GrpcRest.send_request("{{$fullServiceName}}", "{{.Name}}", grpc_request)
end
{{end}}
Expand All @@ -73,12 +83,17 @@ func ProcessService(service *descriptorpb.ServiceDescriptorProto, pkg string) (F
return FileResult{}, routes, err
}
httpMethod, path, err := MethodAndPath(opts.Pattern)
pathInfo, err := ParsedPath(path)
if err != nil {
return FileResult{}, routes, err
}
controllerMethod := method{
Name: strcase.ToSnake(m.GetName()),
RequestType: Classify(m.GetInputType()),
Path: path,
HttpMethod: httpMethod,
Body: opts.Body,
PathInfo: pathInfo,
}
data.Methods = append(data.Methods, controllerMethod)
routes = append(routes, Route{
Expand All @@ -90,12 +105,12 @@ func ProcessService(service *descriptorpb.ServiceDescriptorProto, pkg string) (F
}
resultTemplate, err := template.New("controller").Parse(controllerTemplate)
if err != nil {
return FileResult{}, routes, err
return FileResult{}, routes, fmt.Errorf("can't parse controller template: %w", err)
}
var resultContent bytes.Buffer
err = resultTemplate.Execute(&resultContent, data)
if err != nil {
return FileResult{}, routes, err
return FileResult{}, routes, fmt.Errorf("can't execute controller template: %w", err)
}
return FileResult{
Content: resultContent.String(),
Expand Down
39 changes: 38 additions & 1 deletion protoc-gen-rails/internal/parse.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package internal

import (
"fmt"
"encoding/json"
"fmt"
options "google.golang.org/genproto/googleapis/api/annotations"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"
"regexp"
"strings"
)

func MethodAndPath(pattern any) (string, string, error) {
Expand All @@ -27,6 +30,40 @@ func MethodAndPath(pattern any) (string, string, error) {
}
}

type PathInfo struct {
Name string
ValPattern string
SplitName string
HasValPattern bool
}

func ParsedPath(path string) ([]PathInfo, error) {
var infos []PathInfo
re := regexp.MustCompile("\\{(.*?)}")
matches := re.FindAllString(path, -1)
for _, match := range matches {
name := match[1:len(match)-1]
val := ""
equal := strings.Index(match, "=")
if equal != -1 {
val = name[equal:]
name = name[0:equal-1]
}
splitName := strings.Split(name, ".")
jsonSplit, err := json.Marshal(splitName)
if err != nil {
return nil, fmt.Errorf("error marshalling splitName: %w", err)
}
infos = append(infos, PathInfo{
Name: name,
ValPattern: val,
SplitName: string(jsonSplit),
HasValPattern: val != "",
})
}
return infos, nil
}

func ExtractAPIOptions(meth *descriptorpb.MethodDescriptorProto) (*options.HttpRule, error) {
if meth.Options == nil {
return nil, nil
Expand Down

0 comments on commit 9a096f2

Please sign in to comment.