gogo / letmegrpc Goto Github PK
View Code? Open in Web Editor NEW[maintainer wanted] generates a web form gui from a grpc specification
License: BSD 3-Clause "New" or "Revised" License
[maintainer wanted] generates a web form gui from a grpc specification
License: BSD 3-Clause "New" or "Revised" License
Hi guys,
Hope you are all well !
Would be awesome and a game changer for the golang community to have an administration panel being able to create forms through admin-rest boilerplates like admin-on-rest (https://github.com/marmelab/admin-on-rest-demo) or better with vue.js like (vue-admin).
Why ? because there is no boilerplate allowing to deal with custom forms (settings, multi-database connection or api gateways, eg krakend or qor an e-commerce framework, and to make it easy to setup or edit more flexible admin uis.
Flow:
1- export models, structs or interfaces
2- generate proto files from go source code (eg, link) or from gorm models
3- add/update the yaml based schema (eg, redis-orm) some form properties (eg. textarea, mandatory)
I found some interesting entity based apis, like entity-rest-api, to integrate another admin skeleton from marmelab, ng-admin, in golang but the painful side is that you have to bundle the api manually.
Would be awesome to get things more easier to setup by exporting the schema of gorm model, or struct, and to use letmegrpc to generate the GRPC form and save the form content...
My question is much more about how do u see letmegrpc helping such purpose guys ? Did I miss-understood the aim of letmegrpc ?
It is really something missing in the go community, a dynamic/flexible admin boilerplate.
Have an awesome day ! Waiting for any feedbacks :-) ^^
Cheers,
Richard
$ letmegrpc --addr=localhost:12345 --port=10000 --proto_path=./:../ ./protobuf/proxygroup.proto
2015/07/25 21:33:37 main.go:3:8: no buildable Go source files in /var/folders/_n/hr82ybg110jbm8ytkqygh6zw0000gn/T/letmegrpc_c25416e49fd6e592/src/tmpprotos
exit status 1
running the above command with options results in the above error. Any suggestions? Anything you need for me to diagnose further?
db_dealer.zip
protoc-gen-gofast generates DbDealer_UtolsoMod from the proto name db_dealer__utolso_mod.
The protoc-gen-letmegrpc plugin uses the names from the proto unchanged. I've tried to replicate what gofast does (vanity and vanity/command) but seems a little bit magic, and when it worked, it did not compile, missed the "Serve" function from the html plugin.
Please help me sort this out!
package main
import (
"strings"
"github.com/gogo/letmegrpc/html"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/protoc-gen-gogo/generator"
"github.com/gogo/protobuf/vanity/command"
)
func main() {
req := command.Read()
//files := req.GetProtoFile()
//files = vanity.FilterFiles(files, vanity.NotGoogleProtobufDescriptorProto)
//vanity.ForEachFile(files, vanity.TurnOnMarshalerAll)
//vanity.ForEachFile(files, vanity.TurnOnSizerAll)
//vanity.ForEachFile(files, vanity.TurnOnUnmarshalerAll)
//resp := command.Generate(req)
//command.Write(resp)
gen := generator.New()
gen.Request = req
gen.CommandLineParameters(gen.Request.GetParameter())
gen.WrapTypes()
gen.SetPackageNames()
gen.BuildTypeNameMap()
gen.GeneratePlugin(html.New())
gen.Response = resp
for i := 0; i < len(gen.Response.File); i++ {
gen.Response.File[i].Name = proto.String(strings.Replace(*gen.Response.File[i].Name, ".pb.go", ".letmegrpc.go", -1))
}
// Send back the results.
command.Write(gen.Response)
}
The cli doesn't pass multiple proto files if provided and then each generated file contains an htmlstringer definition (among others).
$ letmegrpc --addr=localhost:12345 --port=8080 serve.proto
2018/08/18 12:21:51 protoc-gen-gogo: program not found or is not executable
--gogo_out: protoc-gen-gogo: Plugin failed with status code 1.
I tried to setup a container running letmegrpc, with the following Dockerfile
FROM golang:latest
# install protobuf
RUN apt-get update && apt-get install curl unzip -y
RUN curl -OL https://github.com/google/protobuf/releases/download/v3.0.0/protoc-3.0.0-linux-x86_64.zip \
&& unzip protoc-3.0.0-linux-x86_64.zip -d protoc3 \
&& mv protoc3/bin/protoc /usr/bin/protoc
# install letmegrpc
RUN cd $GOPATH \
&& mkdir -p ./src/github.com/gogo/letmegrpc \
&& git clone https://github.com/gogo/letmegrpc ./src/github.com/gogo/letmegrpc \
&& git clone https://github.com/gogo/protobuf ./src/github.com/gogo/protobuf \
&& go get google.golang.org/grpc \
&& go get golang.org/x/net/context \
&& (cd ./src/github.com/gogo/letmegrpc && make install)
# install protoc-gen-gogo
RUN go get github.com/gogo/protobuf/protoc-gen-gofast \
&& go get github.com/gogo/protobuf/proto \
&& go get github.com/gogo/protobuf/jsonpb \
&& go get github.com/gogo/protobuf/protoc-gen-gogo \
&& go get github.com/gogo/protobuf/gogoproto
COPY protos /etc/protos
EXPOSE 5000
CMD letmegrpc --addr=localhost:3002 --port=5000 --proto_path=/etc/protos /etc/protos/auth.proto
I tried to run it using docker run -it -p 5000:5000 letmegrpc:auth
, The process run without any errors, but http://localhost:5000/MyService/MyMethod still cannot be reached, any idea where the issues are? Thanks in advance!
This is a great project! But why does the generated UI submit form values as URL parameters instead in a GET request, instead of as form POST parameters? Is there a configuration option to make the UI use POST?
../../1.letmegrpc.go:8248: this.client.setVehicleModel undefined (type OneWayTicketClient has no field or method setVehicleModel, but does have SetVehicleModel)
if change setVehicleModel to SetVehicleModel, it works.
I get the following error when I try to generate a GUI with letmegrpc:
2019/11/16 14:14:37 google/protobuf/any.proto: File not found.
google/protobuf/descriptor.proto: File not found.
google/protobuf/timestamp.proto: File not found.
todo_list.proto: Import "google/protobuf/any.proto" was not found or had errors.
todo_list.proto: Import "google/protobuf/descriptor.proto" was not found or had errors.
todo_list.proto: Import "google/protobuf/timestamp.proto" was not found or had errors.
todo_list.proto:58:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:59:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:60:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:72:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:73:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:74:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:87:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:88:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:89:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:104:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:105:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:106:5: "google.protobuf.Timestamp" is not defined.
todo_list.proto:150:5: "google.protobuf.FileDescriptorSet" is not defined.
todo_list.proto:153:5: "google.protobuf.Any" is not defined.
exit status 1
Check the original proto schema below for more details about the message types.
syntax = "proto3";
import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";
import "google/protobuf/timestamp.proto";
/*
* Services
*/
service TodoList {
// Gets a todo item by id
rpc GetItem (GetItemReq) returns (GetItemResp) {}
// Adds a new item to the todo list
rpc AddItem (AddItemReq) returns (AddItemResp) {}
// Updates a todo items task
rpc UpdateItem (UpdateItemReq) returns (UpdateItemResp) {}
// Deletes a todo item by id
rpc DeleteItem (DeleteItemReq) returns (DeleteItemResp) {}
// Marks a todo item as DONE
rpc MarkItemAsDone (MarkItemDoneReq) returns (MarkItemDoneResp) {}
// Marks a todo item as ONGOING
rpc MarkItemAsOnGoing (MarkItemOnGoingReq) returns (MarkItemOnGoingResp) {}
// Streams a list of todo items from the server to the client
rpc GetItemsStream (GetItemsStreamReq) returns (stream GetItemResp) {}
// Bidirectional streaming RPC where the client streams AddTodoItemRequest
// messages and the server streams TodoItem responses
rpc AddItemsSteam (stream AddItemReq) returns (stream AddItemResp) {}
}
/**
* Messages
*/
enum Priority {
PRIORITY_UNSPECIFIED = 0;
PRIORITY_LOW = 1;
PRIORITY_MEDIUM = 2;
PRIORITY_HIGH = 3;
}
enum Status {
STATUS_UNSPECIFIED = 0;
STATUS_ONGOING = 1;
STATUS_DONE = 2;
}
message TodoItem {
string id = 1;
string task = 2;
Priority priority = 3;
Status status = 4;
google.protobuf.Timestamp created_at = 5;
google.protobuf.Timestamp updated_at = 6;
google.protobuf.Timestamp completed_at = 7;
}
message GetItemReq {
string id = 1;
}
message GetItemResp {
string id = 1;
string task = 2;
Priority priority = 3;
Status status = 4;
google.protobuf.Timestamp created_at = 5;
google.protobuf.Timestamp updated_at = 6;
google.protobuf.Timestamp completed_at = 7;
}
message AddItemReq {
string task = 1;
Priority priority = 2;
}
message AddItemResp {
string id = 1;
string task = 2;
Priority priority = 3;
Status status = 4;
google.protobuf.Timestamp created_at = 5;
google.protobuf.Timestamp updated_at = 6;
google.protobuf.Timestamp completed_at = 7;
}
message UpdateItemReq {
string id = 1;
string task = 2;
Priority priority = 3;
Status status = 4;
}
message UpdateItemResp {
string id = 1;
string task = 2;
Priority priority = 3;
Status status = 4;
google.protobuf.Timestamp created_at = 5;
google.protobuf.Timestamp updated_at = 6;
google.protobuf.Timestamp completed_at = 7;
}
message DeleteItemReq {
string id = 1;
}
message DeleteItemResp {
string id = 1;
bool success = 2;
string message = 3;
}
message MarkItemDoneReq {
string id = 1;
}
message MarkItemDoneResp {
string id = 1;
bool success = 2;
string message = 3;
}
message MarkItemOnGoingReq {
string id = 1;
}
message MarkItemOnGoingResp {
string id = 1;
bool success = 2;
string message = 3;
}
message GetItemsStreamReq {
int32 limit = 1;
}
message GetItemsStreamResp {
repeated TodoItem items = 1;
uint32 cursor = 2;
}
message SelfDescribingMessage {
// Set of FileDescriptorProtos which describe the type and its dependencies.
google.protobuf.FileDescriptorSet descriptor_set = 1;
// The message and its type, encoded as an Any message.
google.protobuf.Any message = 2;
}
I'm just trying to run the example in the readme but when I run the final line in the example:
letmegrpc --addr=localhost:12345 --port=8080 serve.proto
I get This parser only recognizes "proto2". exit status 1
How do I fix this?
I'm trying to run the example as
letmetestserver --port=8080 && letmegrpc --addr=localhost:3149 --port=8080 serve.proto
However, running curl localhost:8080
returns curl: (56) Recv failure: Connection reset by peer
For reference, I'm running this server and attempting to curl on the same machine. curl localhost:3149
simply says Connection refused
Any solutions?
» letmegrpc --addr=localhost:65021 --port=8080 -proto_path ~/go/src/content_api/domains/border/category ~/go/src/content_api/domains/border/category/category.proto
2016/09/05 19:03:53 panic: runtime error: index out of range
goroutine 1 [running]:
panic(0x55e280, 0xc42000a180)
/usr/lib/go/src/runtime/panic.go:500 +0x1a1
github.com/gogo/letmegrpc/html.(*html).generateFormFunc(0xc4200f3570, 0xc4200efd82, 0xe, 0xc4200134a0)
/home/u/go/src/github.com/gogo/letmegrpc/html/html.go:93 +0x4e1
github.com/gogo/letmegrpc/html.(*html).Generate(0xc4200f3570, 0xc4200da1b0)
/home/u/go/src/github.com/gogo/letmegrpc/html/html.go:169 +0x2dce
github.com/gogo/protobuf/protoc-gen-gogo/generator.(*Generator).generatePlugin(0xc42009e000, 0xc4200da1b0, 0x63c7e0, 0xc4200f3570)
/home/u/go/src/github.com/gogo/protobuf/protoc-gen-gogo/generator/helper.go:330 +0x142
github.com/gogo/protobuf/protoc-gen-gogo/generator.(*Generator).GeneratePlugin(0xc42009e000, 0x63c7e0, 0xc4200f3570)
/home/u/go/src/github.com/gogo/protobuf/protoc-gen-gogo/generator/helper.go:309 +0x22d
main.main()
/home/u/go/src/github.com/gogo/letmegrpc/protoc-gen-letmegrpc/main.go:59 +0x32e
--letmegrpc_out: protoc-gen-letmegrpc: Plugin failed with status code 2.
exit status 1
The directory list for GOPATH is concatenated using envs[i] + ":" + tmpDir
. But Windows needs it to be envs[i] + ";" + tmpDir
since the list separator is a semicolon.
That would be very nice, to be able to call one of several grpc servers listening on the same HTTPS port, but under different paths. grpc.Server.ServeHTTP allows us to create such a server, but I don't know yet how to call it with letmegrpc.
I need to use grpc.Invoke(..., "/prefixpath/package.service/method", ...)
(instead of "/package/service.method").
I don't see an easy solution, as all the client code is generated, with constants as paths.
It would be great if it was possible to annotate protobuf fields and have those fields appear as tooltips in the generated web form. This could be used to provide instructions and act as living documentation.
I am trying to run letmegrpc but the generated code is incorrect:
letmegrpc --addr=localhost:3149 --port=8080 listdates.proto
2017/03/10 11:00:35 # tmpprotos
../../listdates.letmegrpc.go:54: conn declared and not used
Unfortunately there is a lot of implicit stuff going on. I found the generated file is in some /tmp/letmegrpc_ directory, and the code is indeed incorrect:
func NewHandler(grpcAddr string, stringer func(req, resp interface{}) ([]byte, error), opts ...google_golang_org_grpc.DialOption) (net_http.Handler, error) {
conn, err := google_golang_org_grpc.Dial(grpcAddr, opts...)
if err != nil {
return nil, err
}
mux := net_http.NewServeMux()
return mux, nil
}
Indeed this is not correct go code.
It is generated with this code
What can we do about it?
Related question: I see the code generator uses gogo/protobuf code generator, with .In(), .Out(), etc. Is there a reason to do it like this? Would it not be much simpler to generate the code with a template, and format it with gofmt afterwards?
Last release
https://github.com/golang/protobuf/blob/master/protoc-gen-go/grpc/grpc.go#L51
uses
grpc.SupportPackageIsVersion4
It looks like oneof is not supported. The JSON doesn't seem to be marshalled onto the oneof structure correctly. The oneof is ofcourse defined as interface field using the is_ type.
Maybe there's a custom unmarshal function required, or a different work arround (sending the oneof type and value as seperate json?
If you use '%' in any string field, the character will not be correctly escaped when passed via the json
GET querystring parameter.
This is the diff I used to narrow down the bug:
diff --git a/myservice-letmegrpc/myservice.letmegrpc.go b/myservice-letmegrpc/myservice.letmegrpc.go
index 389156e..9f8b747 100644
--- a/myservice-letmegrpc/myservice.letmegrpc.go
+++ b/myservice-letmegrpc/myservice.letmegrpc.go
@@ -35,7 +35,10 @@ It has these top-level messages:
*/
package myservice
-import net_http "net/http"
+import (
+ net_http "net/http"
+ "net/url"
+)
import encoding_json "encoding/json"
import io "io"
import golang_org_x_net_context "golang.org/x/net/context"
@@ -2437,7 +2440,17 @@ s += '<div class="children" type="Something_something">' + buildSomething_som
func (this *htmlmyservice) CreateSomething(w net_http.ResponseWriter, req *net_http.Request) {
w.Write([]byte(Header(`myservice`, `CreateSomething`)))
- jsonString := req.FormValue("json")
+
+ rawQuery := req.URL.RawQuery[len("json="):]
+ fmt.Println("raw query =", rawQuery)
+
+ // jsonString := req.FormValue("json")
+ jsonString, err := url.QueryUnescape(rawQuery)
+ if err != nil {
+ w.Write([]byte("<div class=\"alert alert-danger\" role=\"alert\">" + err.Error() + "</div>"))
+ return
+ }
+
someValue := false
msg := &CreateSomethingRequest{}
if len(jsonString) > 0 {
@@ -2450,6 +2463,8 @@ func (this *htmlmyservice) CreateSomething(w net_http.ResponseWriter, req
w.Write([]byte("<div class=\"alert alert-danger\" role=\"alert\">" + err.Error() + "</div>"))
}
someValue = true
+ } else {
+ w.Write([]byte("<div class=\"alert alert-info\" role=\"alert\">" + `No JSON sent` + "</div>"))
}
w.Write([]byte(Formmyservice_CreateSomething))
if someValue {
Hi,
Conflicts happen after generating separate files that are a part of the same package.
Such generated files have functions and variables with the same name which causes issues.
Example:
Lets say I have 2 files in "package example" named ex1.proto and ex2.proto.
When I run protoc --letmegrpc (...) I get var Header, var Footer, and function func NewHandler defined in both ex1.letmegrpc.go and ex2.letmegrpc.go which causes issues.
I may have a workaround for this issue.
When working remotely, one may want to specify an IP in local network's range (or for some unfathomable reason, listen on all interfaces or on a public IP).
A trivial fix would be to replace httpPort
flag with httpAddr
, and to use that in the generated code. If port
flag is specified, the program could keep the current behavior.
I just tried to use the default addressbook.proto example. The function buildRepeatedKeyword_PhoneNumber_phones
is generated, but where it's used, it want's to call buildRepeatedKeyword__phones
. I just started looking into the problem, but I assume the getMessage
in form.go
seems to have a problem with subtypes. I will check if I can fix it in little time. If not, I will have to just drop my tests of letmegrpc
, since this is already the second problem I found in less than an hour and I don't want to get from one problem into the next.
This happens if GOPATH is not set. On Mac OS the default behavior is to use ~/go if GOPATH is not set. I am not sure this is the case for all go installations.
Workaround:
set GOPATH
on OSX, go 1.5.1
i used the deps.sh to install. The git-anchor technique looks cool solution. But i think i hit some snaffu's
(cd ./src/github.com/gogo/letmegrpc && make install)
go install -v ./...
github.com/gogo/protobuf/proto
golang.org/x/net/context
golang.org/x/net/internal/timeseries
google.golang.org/grpc/codes
google.golang.org/grpc/grpclog
github.com/bradfitz/http2/hpack
google.golang.org/grpc/credentials
golang.org/x/net/trace
google.golang.org/grpc/metadata
github.com/bradfitz/http2
github.com/gogo/letmegrpc/testcmd
google.golang.org/grpc/transport
github.com/gogo/protobuf/protoc-gen-gogo/descriptor
google.golang.org/grpc
github.com/gogo/protobuf/gogoproto
github.com/gogo/protobuf/protoc-gen-gogo/plugin
github.com/gogo/letmegrpc/letmetestserver/serve
github.com/gogo/letmegrpc/test
github.com/gogo/letmegrpc/testproto2
github.com/gogo/protobuf/protoc-gen-gogo/generator
# github.com/gogo/letmegrpc/letmetestserver/serve
letmetestserver/serve/serve.pb.go:269: cannot use _Label_Produce_Handler (type func(interface {}, context.Context, func(interface {}) error) (interface {}, error)) as type grpc.methodHandler in field value
letmetestserver/serve/serve.pb.go:273: cannot use _Label_Loop_Handler (type func(interface {}, context.Context, func(interface {}) error) (interface {}, error)) as type grpc.methodHandler in field value
# github.com/gogo/letmegrpc/test
test/grpc.pb.go:303: cannot use _MyTest_UnaryCall_Handler (type func(interface {}, context.Context, func(interface {}) error) (interface {}, error)) as type grpc.methodHandler in field value
# github.com/gogo/letmegrpc/testproto2
testproto2/proto2.pb.go:355: cannot use _Proto2_Produce_Handler (type func(interface {}, context.Context, func(interface {}) error) (interface {}, error)) as type grpc.methodHandler in field value
github.com/gogo/letmegrpc/form
github.com/gogo/letmegrpc/html
github.com/gogo/letmegrpc/protoc-gen-letmegrpc
make: *** [install] Error 2
With support for reflection in Go, it would be great if letmegrpc could supports rendering from a proto file descriptor.
Given a.proto
and b.proto
, if b.proto
imports a.proto
and uses an object, say c
, any comments within c
from a.proto
will not be generated.
a.proto
:
message C {
// This comment doesn't get turned into a tooltip
required int64 something = 1;
}
b.proto
:
message WrapperMsg {
// This message does
required a.C nested = 1;
}
Is it possible for the parser to process imported .proto
files and their comments?
If protobuf fields' comments contain any quote-like symbols then something usually breaks.
i.e. ` breaks go code and ' breaks javascript.
I'll fix it later if nobody else picks the issue up first,
As I've investigated, the comments before the field (in the .proto file) are read and provided to Builder.
But I don't see this appear anywhere.
There's a "setLink" in the js code, but nowhere called.
What do I miss?
Currently on the first ampersand is escaped, but all of the ampersands should be escaped
It would be nice if streaming grpc methods will be supported
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.