Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go で始める JSON-RPC 入門

Go で始める JSON-RPC 入門

C3d309cfa22d888d93a6187b786d1998?s=128

Osamu TONOMORI

December 12, 2016
Tweet

More Decks by Osamu TONOMORI

Other Decks in Programming

Transcript

  1. Go Ͱ࢝ΊΔ JSON-RPC ೖ໳ @osamingo golang.tokyo #2 (2016/12/12)

  2. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  3. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  4. ࣗݾ঺հ

  5. ࣗݾ঺հ • ओ৿ ཧ - Osamu TONOMORI • @osamingo •

    גࣜձࣾι΢κ΢ • 2016/08 ~ • Software engineer • Go ྺ • 2014/10 ~ • 3 services • <3 Live, Juggling, Voice Percussion 5
  6. None
  7. None
  8. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  9. JSON-RPC #ͱ͸

  10. JSON-RPC #ͱ͸ • JSON Λར༻ͨ͠ɺRemote Procedure Call Ͱ͢ɻ • Content-Type:

    “application/json" • Path: “/jrpc” • Specification ͕ɺ΄΅ϖϥΠν͔͠ͳ͍ɻ • ৽֮͑͘͠Δ͜ͱ͸ɺ΄΅ͳ͍ɻ • http://www.jsonrpc.org/specification 10
  11. None
  12. JSON-RPC Example - Request 12 1 { 2 "jsonrpc": "2.0",

    3 "method": "Echo", 4 "params": { 5 "name": "John Doe" 6 }, 7 "id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b" 8 }
  13. JSON-RPC Example - Response 13 1 { 2 "jsonrpc": "2.0",

    3 "result": { 4 "message": "Hello, John Doe" 5 }, 6 "id": "243a718a-2ebb-4e32-8cc8-210c39e8a14b" 7 }
  14. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  15. ඪ४ Package Ͱͷ JSON-RPC

  16. ඪ४ Package Ͱͷ JSON-RPC • Go ͸ɺඪ४Ͱ JSON-RPC Λαϙʔτ͍ͯ͠·͢ɻ •

    import “net/rpc/jsonrpc” • Go BlogͰ΋঺հ͋ΔͷͰׂΓͱ஌͍ͬͯΔਓଟ͍͔΋ • https://blog.golang.org/json-rpc-tale-of-interfaces 16
  17. JSON-RPC by net/rpc/jsonrpc 1 package main 2 3 import (

    4 "io" 5 "log" 6 "net" 7 "net/http" 8 "net/rpc" 9 "net/rpc/jsonrpc" 10 ) 11 12 type ( 13 Arithmetic struct{} 14 MultiplyArgs struct { 15 A, B int 16 } 17 MultiplyResult struct { 18 Result int 19 } 20 ) 21 22 func (a *Arithmetic) Multiply(args *MultiplyArgs, reply *MultiplyResult) error { 23 reply.Result = args.A * args.B 24 return nil 25 } 26 27 func init() { 28 s := rpc.NewServer() 29 arithmetic := &Arithmetic{} 30 s.Register(arithmetic) 31 http.HandleFunc("/jrpc", func(w http.ResponseWriter, r *http.Request) { 32 conn, _, err := w.(http.Hijacker).Hijack() 33 if err != nil { 34 log.Fatalln(err) 35 } 36 s.ServeCodec(jsonrpc.NewServerCodec(conn)) 37 }) 38 39 go http.ListenAndServe(":8080", nil) 40 } 41 42 func main() { 43 conn, err := net.Dial("tcp", "localhost:8080") 44 if err != nil { 45 log.Fatalln(err) 46 } 47 io.WriteString(conn, "CONNECT "+"/jrpc"+" HTTP/1.0\n\n") 48 if err != nil { 49 log.Fatalln(err) 50 } 51 cli := jsonrpc.NewClient(conn) 52 var ret MultiplyResult 53 err = cli.Call("Arithmetic.Multiply", &MultiplyArgs{A: 5, B: 5}, &ret) 54 if err != nil { 55 log.Fatalln(err) 56 } 57 defer cli.Close() 58 log.Println(ret.Result) 59 } https://git.io/v1gpF 17
  18. JSON-RPC by net/rpc/jsonrpc • ·ͣ͸ɺड͚෇͚Δ Method Λ༻ҙ͢Δɻ 12 type (

    13 Arithmetic struct{} 14 MultiplyArgs struct { 15 A, B int 16 } 17 MultiplyResult struct { 18 Result int 19 } 20 ) 21 22 func (a *Arithmetic) Multiply(args *MultiplyArgs, reply *MultiplyResult) error { 23 reply.Result = args.A * args.B 24 return nil 25 } 18
  19. JSON-RPC by net/rpc/jsonrpc • RPC Server ʹొ࿥͢Δɻ • HTTP Ͱͷ

    Handling Λઃఆ͢Δɻ 27 func init() { 28 s := rpc.NewServer() 29 arithmetic := &Arithmetic{} 30 s.Register(arithmetic) 31 http.HandleFunc("/jrpc", func(w http.ResponseWriter, r *http.Request) { 32 conn, _, err := w.(http.Hijacker).Hijack() 33 if err != nil { 34 log.Fatalln(err) 35 } 36 s.ServeCodec(jsonrpc.NewServerCodec(conn)) 37 }) 38 39 go http.ListenAndServe(":8080", nil) 40 } 19
  20. JSON-RPC by net/rpc/jsonrpc • ϝιου໊Λࢦఆͯ͠ CONNECT͢Δɻ 42 func main() {

    43 conn, err := net.Dial("tcp", "localhost:8080") 44 if err != nil { 45 log.Fatalln(err) 46 } 47 io.WriteString(conn, "CONNECT "+"/jrpc"+" HTTP/1.0\n\n") 48 if err != nil { 49 log.Fatalln(err) 50 } 51 cli := jsonrpc.NewClient(conn) 52 var ret MultiplyResult 53 err = cli.Call("Arithmetic.Multiply", &MultiplyArgs{A: 5, B: 5}, &ret) 54 if err != nil { 55 log.Fatalln(err) 56 } 57 defer cli.Close() 58 log.Println(ret.Result) 59 } 20
  21. JSON-RPC by net/rpc/jsonrpc • Debug ػೳ΋͍ͭͯΔ 21

  22. ݸਓతͳײ૝ • ࣮૷Λ௨ͯ͠ɺ RPC ΛϨΫνϟʔͯ͘͠Ε͍ͯΔɻ • JSON-RPC 2.0 ͷ Spec

    Λຬ͍ͨͯ͠ͳ͍ɻ • HTTP Ͱड͚औΔ࣌ʹͪΐͬͱख͕͔͔ؒΔɻ • Reflect ͕ɺଟ͍ؾ͕͢Δɻ 22
  23. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  24. Third Party Package Ͱͷ JSON-RPC

  25. Gorilla Toolkit ͷ JSON-RPC • Gorilla Toolkit ͕ɺ Spec Λىͯ͘͜͠Ε͍ͯΔɻ

    • import “github.com/gorilla/rpc/v2/json2" • Interface ͕ɺѻ͍΍͘͢ͳ͍ͬͯΔɻ 25
  26. JSON-RPC by Gorilla Toolkit https://git.io/v1VeT 26 1 package main 2

    3 import ( 4 "bytes" 5 "log" 6 "net/http" 7 8 "github.com/gorilla/rpc/v2" 9 "github.com/gorilla/rpc/v2/json2" 10 ) 11 12 type ( 13 Arithmetic struct{} 14 MultiplyArgs struct { 15 A, B int 16 } 17 MultiplyResult struct { 18 Result int 19 } 20 ) 21 22 func (a *Arithmetic) Multiply(r *http.Request, args *MultiplyArgs, reply *MultiplyResult) error { 23 reply.Result = args.A * args.B 24 return nil 25 } 26 27 func init() { 28 s := rpc.NewServer() 29 s.RegisterCodec(json2.NewCodec(), "application/json") 30 arithmetic := &Arithmetic{} 31 s.RegisterService(arithmetic, "") 32 http.Handle("/jrpc", s) 33 go http.ListenAndServe(":8080", nil) 34 } 35 36 func main() { 37 resp, err := http.Post("http://localhost:8080/jrpc", "application/json", 38 bytes.NewBufferString(`{ 39 "jsonrpc": "2.0", 40 "method": "Arithmetic.Multiply", 41 "params": { 42 "A": 10, 43 "B": 10 44 }, 45 "id": 123 46 }`)) 47 if err != nil { 48 log.Fatalln(err) 49 } 50 defer resp.Body.Close() 51 var ret MultiplyResult 52 err = json2.DecodeClientResponse(resp.Body, &ret) 53 if err != nil { 54 log.Println("aaa") 55 log.Fatalln(err) 56 } 57 log.Println(ret.Result) 58 }
  27. JSON-RPC by Gorilla Toolkit • http.Request ͕ड͚औΕΔ༷ʹͳ͍ͬͯΔɻ 27 22 func

    (a *Arithmetic) Multiply(r *http.Request, args *MultiplyArgs, reply *MultiplyResult) error { 23 reply.Result = args.A * args.B 24 return nil 25 }
  28. JSON-RPC by Gorilla Toolkit • net.Conn ΛऔΓճ͞ͳͯ͘΋େৎ෉ʹͳ͍ͬͯΔɻ • Content-Type ͱ

    Codec ΛηοτͰఆٛͰ͖Δɻ 28 27 func init() { 28 s := rpc.NewServer() 29 s.RegisterCodec(json2.NewCodec(), "application/json") 30 arithmetic := &Arithmetic{} 31 s.RegisterService(arithmetic, "") 32 http.Handle("/jrpc", s) 33 go http.ListenAndServe(":8080", nil) 34 }
  29. JSON-RPC by Gorilla Toolkit • ݟͨ͜ͱ͋Δ HTTP Request ͷඈ͹͠ํͰΠέΔɻ 29

    36 func main() { 37 resp, err := http.Post("http://localhost:8080/jrpc", "application/json", 38 bytes.NewBufferString(`{ 39 "jsonrpc": "2.0", 40 "method": "Arithmetic.Multiply", 41 "params": { 42 "A": 10, 43 "B": 10 44 }, 45 "id": 123 46 }`)) 47 if err != nil { 48 log.Fatalln(err) 49 } 50 defer resp.Body.Close() 51 var ret MultiplyResult 52 err = json2.DecodeClientResponse(resp.Body, &ret) 53 if err != nil { 54 log.Println("aaa") 55 log.Fatalln(err) 56 } 57 log.Println(ret.Result) 58 }
  30. ݸਓతͳײ૝ • ඪ४ Package Λ౿ऻ͠ɺѻ͍΍͘͢ͳ͍ͬͯΔɻ • Go 1.6 ҎԼͩͱɺ context

    Λ࣋ͪӡ΂ͳ͍ɻ • ͢͜͠खͷಧ͔ͳ͍෦෼͕͋Δɻ
 ྫʣCustom Error ࣌ͷ Data ͷॻ͖ࠐΊͳ͍౳ 30
  31. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  32. Φεεϝͷ Package

  33. ͳ͍

  34. ͷͰɺ࡞Γ·ͨ͠ɻ

  35. github.com/osamingo/jsonrpc

  36. JSON-RPC by osamingo/jsonrpc • ؆ૉͳ࣮૷ • context Λ࣋ͪӡ΂Δ • ΑΓৄࡉͳ

    Debug ػೳ 36
  37. JSON-RPC by osamingo/jsonrpc 37 1 package main 2 3 import

    ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "log" 8 "net/http" 9 10 "github.com/osamingo/jsonrpc" 11 ) 12 13 type ( 14 MultiplyParams struct { 15 A, B int 16 } 17 MultiplyResult struct { 18 Result int 19 } 20 ) 21 22 var _ jsonrpc.Func = Multiply 23 24 func Multiply(c context.Context, params *json.RawMessage) (interface{}, *jsonrpc.Error) { 25 var p MultiplyParams 26 if err := jsonrpc.Unmarshal(params, &p); err != nil { 27 return nil, err 28 } 29 return MultiplyResult{ 30 Result: p.A * p.B, 31 }, nil 32 } 33 34 func init() { 35 jsonrpc.RegisterMethod("Arithmetic.Multiply", Multiply, MultiplyParams{}, MultiplyResult{}) 36 http.HandleFunc("/jrpc", jsonrpc.Handler) 37 http.HandleFunc("/jrpc/debug", jsonrpc.DebugHandler) 38 go http.ListenAndServe(":8080", nil) 39 } 40 41 func main() { 42 resp, err := http.Post("http://localhost:8080/jrpc", "application/json", 43 bytes.NewBufferString(`{ 44 "jsonrpc": "2.0", 45 "method": "Arithmetic.Multiply", 46 "params": { 47 "A": 15, 48 "B": 15 49 }, 50 "id": 456 51 }`)) 52 if err != nil { 53 log.Fatalln(err) 54 } 55 defer resp.Body.Close() 56 var body jsonrpc.Response 57 if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { 58 log.Fatalln(err) 59 } 60 log.Println(body.Result.(map[string]interface{})["Result"]) 61 } https://git.io/v1Vew
  38. JSON-RPC by osamingo/jsonrpc • jsonrpc.Func Λຬͨؔ͢਺Λఆٛ͢Δɻ 38 13 type (

    14 MultiplyParams struct { 15 A, B int 16 } 17 MultiplyResult struct { 18 Result int 19 } 20 ) 21 22 var _ jsonrpc.Func = Multiply 23 24 func Multiply(c context.Context, params *json.RawMessage) (interface{}, *jsonrpc.Error) { 25 var p MultiplyParams 26 if err := jsonrpc.Unmarshal(params, &p); err != nil { 27 return nil, err 28 } 29 return MultiplyResult{ 30 Result: p.A * p.B, 31 }, nil 32 }
  39. JSON-RPC by osamingo/jsonrpc • Method Λొ࿥͠ɺEndpoint Λఆٛ͢Δɻ 39 34 func

    init() { 35 jsonrpc.RegisterMethod("Arithmetic.Multiply", Multiply, MultiplyParams{}, MultiplyResult{}) 36 http.HandleFunc("/jrpc", jsonrpc.Handler) 37 http.HandleFunc("/jrpc/debug", jsonrpc.DebugHandler) 38 go http.ListenAndServe(":8080", nil) 39 }
  40. JSON-RPC by osamingo/jsonrpc • Request ͸ɺGorilla ͱ΄΅มΘΒͳ͍ײ͡ɻ 40 41 func

    main() { 42 resp, err := http.Post("http://localhost:8080/jrpc", "application/json", 43 bytes.NewBufferString(`{ 44 "jsonrpc": "2.0", 45 "method": "Arithmetic.Multiply", 46 "params": { 47 "A": 15, 48 "B": 15 49 }, 50 "id": 456 51 }`)) 52 if err != nil { 53 log.Fatalln(err) 54 } 55 defer resp.Body.Close() 56 var body jsonrpc.Response 57 if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { 58 log.Fatalln(err) 59 } 60 log.Println(body.Result.(map[string]interface{})["Result"]) 61 }
  41. JSON-RPC by osamingo/jsonrpc • MethodRepository ͱ͍͏ܗͰɺmap Λ࢖ͬͯ
 ϝιου໊ͱؔ਺ͷϙΠϯλΛඥ෇͚͍ͯ·͢ɻ • Go

    ͷόʔδϣϯʹ͔͔ΘΒͣɺcontext ͷ࣋ͪӡͼʹ
 ରԠ͍ͯ͠·͢ɻʢ<3 GAE/SEʣ 41
  42. ͱ͸͍͑ • JSON-RPC ͩͱɺSwagger ͱ͔ɺAPI Blueprint ͱ͔
 ࢖͑ͳͯ͘ɺ݁ہίʔυಡΜͰԼ͍͞ͱ͔͠ݴ͑ͳ͍݅ 42

  43. ͱ͸͍͑ • JSON-RPC ͩͱɺSwagger ͱ͔ɺAPI Blueprint ͱ͔
 ࢖͑ͳͯ͘ɺ݁ہίʔυಡΜͰԼ͍͞ͱ͔͠ݴ͑ͳ͍݅ => Debug

    ػೳ࢖͑͹ JSON Schema ͕ฦͬͯ͘Δɻ 43
  44. JSON-RPC by osamingo/jsonrpc 44 1 [ 2 { 3 "name":

    "Arithmetic.Multiply", 4 "function": "main.Multiply", 5 "params": { 6 "$ref": "#/definitions/MultiplyParams", 7 "definitions": { 8 "MultiplyParams": { 9 "type": "object", 10 "properties": { 11 "A": { 12 "type": "integer" 13 }, 14 "B": { 15 "type": "integer" 16 } 17 }, 18 "additionalProperties": false, 19 "required": [ 20 "A", 21 "B" 22 ] 23 } 24 } 25 }, 26 "result": { 27 "$ref": "#/definitions/MultiplyResult", 28 "definitions": { 29 "MultiplyResult": { 30 "type": "object", 31 "properties": { 32 "Result": { 33 "type": "integer" 34 } 35 }, 36 "additionalProperties": false, 37 "required": [ 38 "Result" 39 ] 40 } 41 } 42 } 43 } 44 ] ొ࿥ͯ͋͠Δϝιου໊ Params ͷ JSON Schema Resultͷ JSON Schema
  45. Agenda 1. ࣗݾ঺հ 2. JSON-RPC #ͱ͸ 3. ඪ४ Package Ͱ

    JSON-RPC 4. Third Party Package Ͱͷ JSON-RPC 5. Φεεϝͷ Package 6. ·ͱΊ
  46. ·ͱΊ

  47. ·ͱΊ • JSON-RPC ͸ɺεΰ͘؆୯Ͱ͋Δɻ • Go ݴޠ͸ɺඪ४ Package Ͱαϙʔτ͍ͯ͠Δɻ •

    Gorilla Toolkit ͸ɺJSON-RPC 2.0 Λຬ͍ͨͯ͠Δɻ • osamingo/jsonrpc Λ࢖ͬͯ͘ΕΔͱخ͍͠ɻ
 (awesome-go ʹ΋ొ࿥ࡁΈͩΑɻ)
  48. Next xRPC is … ͱ͸͍͑ɺ࣍དྷΔʢདྷ͍ͯΔʣRPC ͸ɺgRPC Ͱ͢ɻ

  49. Thank you for your attention. ελΠϧ͸ɺ@shoya140 ۘ੡ͷ Zebra Λ࢖Θͤͯ௖͖·ͨ͠ɻ