-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
JSON RPC over HTTP #576
JSON RPC over HTTP #576
Conversation
Add basic server tests, following example from http transport. Switch Response.Error to pointer, to make absence clearer.
Thanks for the props and also moving it forward! I got pulled away to do other things and never got a chance to move forward with it. |
With the caveats that I don't know a whole lot about JSON RPC, and I've only just skimmed the code: the shape of this looks quite good to me. I'll have a few nits to pick in a final review, but otherwise 👍 from me so far. |
I'll try to take a look too. I have used JSON-RPC extensively in the past. |
@rossmcf Just ping me when you're ready for a final review! 👍 |
Thanks @peterbourgon. I should hopefully have some time to tidy it up towards the end of the week. |
@peterbourgon I'm getting a little blind to this now, so would appreciate your input. With regard to examples, would I be best to add a JSON RPC transport to the addsvc? |
Also, any pointers on why the travis build is failing would be useful. I can't make sense of the output. |
This test is racy. It expects the cache to have certain elements, however it's updated concurrently. It's pretty easy to reproduce:
|
@rossmcf @peterbourgon What do you think about https://github.com/rossmcf/kit/compare/json-rpc-over-http...fredipevcin:json-rpc-over-http?expand=1 Idea is that method correlates to service. For every service it is possible to specify logger, before and after instead of only for whole RPC handler. handler := jsonrpc.NewServer(
jsonrpc.ServiceMap{
"add": jsonrpc.NewService(
func(ctx context.Context, request interface{}) (response interface{}, err error) {
return nil, nil
},
func(ctx context.Context, msg json.RawMessage) (interface{}, error) {
return nil, nil
},
func(ctx context.Context, result interface{}) (json.RawMessage, error) {
return []byte(`"result"`), nil
},
jsonrpc.ServiceBefore(func(ctx context.Context, _ http.Header) context.Context {
return ctx
}),
),
},
)
http.Handle("/v1/rpc", handler) Service is not aware about Code is just WIP as I wanted your option on it if it makes sense. |
I'm currently working on JSON-RPC implementation https://github.com/fredipevcin/gokit-jsonrpc which we will use in-house. It is not yet completed. |
@rossmcf Thanks and please forgive my delay! At a glance this seems to be alright. Can you help me review this more thoroughly (and help future users!) by adding a runnable example? I think the best thing would be to add JSON RPC support to examples/addsvc, but I'd also look at something standalone if there were good reasons that weren't feasible. |
Thanks for your feedback, everyone. Test coverage in the package is looking more respectable now, and I think the issues raised have been addressed. Over to you. |
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.
Two outstanding issues from my perspective. Once those are resolved I'm happy to merge!
transport/http/jsonrpc/client.go
Outdated
return &RequestID{ | ||
intValue: int(id), | ||
} | ||
} |
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 isn't goroutine-safe, and the type that includes it (the client) doesn't perform any synchronization. You've got a data race! You need to either put synchronization in the client, and un-export this type or explicitly mark it as not goroutine-safe; or put synchronization in this type directly.
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.
OK, I think that's addressed now, with an atomic.AddUint64 in Generate().
transport/http/jsonrpc/server.go
Outdated
|
||
// ServerBefore functions are executed on the HTTP request object before the | ||
func ServerBefore(before ...httptransport.RequestFunc) ServerOption { | ||
// request is decoded. |
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.
Still got a problem here.
Oh, and the test failure reports
which I reckon is fixable, too. |
Make auto-incrementing IDs goroutine safe. Make RequestIDGenerator interface public.
The client had been using the RequestID type in requests. Making this serialize in a deterministic and predictable way was going to be fiddly, so I decided to allow interface{} for IDs, client-side.
OK, coveralls is finally satisfied. Hopefully that's everything taken care of. |
t.Fatalf("result is not string: (%T)%+v", result, result) | ||
} | ||
if rs != "boogaloo" { | ||
t.Fatalf("want=boogaloo, got=%d", rs) |
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.
# github.com/go-kit/kit/transport/http/jsonrpc_test
transport/http/jsonrpc/client_test.go:190: Fatalf format %d has arg rs of wrong type string
FAIL github.com/go-kit/kit/transport/http/jsonrpc [build failed]
Build failure due to an aggressive lint. |
@peterbourgon Thanks for spotting that. Oddly, it didn't come up when I ran |
Yes! Thank you so much! This is great. I'll cut a release this week, probably. |
Thank you for all of your support with this. In the release notes, might you be able to mention the original contribution of @blainsmith, and my employer, @senseyeio, on whose time I did most of the work for this? |
Any plans for new release? |
Want to wait for 1 or 2 more inflight PRs to land. Sorry for the delay. |
* first pass at JSON RPC HTTP transport * example implementation of JSON RPC over HTTP * Add ID type for JSON RPC Request, with tests. * Add basic server testing for JSON RPC. Add basic server tests, following example from http transport. Switch Response.Error to pointer, to make absence clearer. * Handle unregistered JSON RPC methods. * Package tidy-up. * Test ServerBefore / ServerAfter for JSON RPC. * More JSON RPC tests. * Remove JSON RPC from addsvc example, pending full JSON RPC example. * Remove JSON RPC from addsvc example, pending full JSON RPC example. * Remove context field from jsonrpc.Server. * Add JSON content type to all JSON RPC responses. * Add JSON content type to all JSON RPC responses. * Remove client-side JSON RPC funcs for now. * Document interceptingWriter * Add JSON RPC doc.go. * Add README for JSON RPC. * Wire in JSON RPC addsvc. * Add JSON RPC to Addsvc CLI. * Set JSONRPC version in responses. * Add JSON RPC client to addcli example. * Wire in client middlewares for JSON RPC addsvc example. * Fix rate limiter dependency. * Add concat JSON RPC method. * Improve JSON RPC server test coverage. * Add error tests. * Clarify ErrorCoder in comment. * Make endpoint consistent in README. * Gofmt handler example in README. * Auto-increment client IDs. Allow for customisation. * Add happy-path test for JSON RPC client. * Provide default encoder/decoder in JSON RPC client. * Fix comment line. * RequestIDGenerator tidy-up. Make auto-incrementing IDs goroutine safe. Make RequestIDGenerator interface public. * Fix client ID creation. The client had been using the RequestID type in requests. Making this serialize in a deterministic and predictable way was going to be fiddly, so I decided to allow interface{} for IDs, client-side. * Test client request ID more effectively. * Cover client options in test. * Improve error test coverage. * Fix format spec in test output. * Tweaks to satisfy the linter.
This PR continues @blainsmith's work from #451 to address issue #575.
This is still a work in progress, but I wanted to open the PR early, to invite discussion.
I've taken the liberty of staring a new fork. @blainsmith's commits have been imported, so that he's duly credited.
I've added some tests, and hopefully addressed some of the feedback from the previous PR, namely creating an
RequestID
object with a customJSONUnmarshal
, that can handle IDs as strings, ints or floats. @groob, I'd appreciate your thoughts on that.I'll try to tackle some more of the feedback, regarding server and encoding options in due course.
Thanks in advance for any feedback you can offer.
Ross