Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

ࣗݾ঺հ

Slide 5

Slide 5 text

ࣗݾ঺հ • ओ৿ ཧ - Osamu TONOMORI • @osamingo • גࣜձࣾι΢κ΢ • 2016/08 ~ • Software engineer • Go ྺ • 2014/10 ~ • 3 services • <3 Live, Juggling, Voice Percussion 5

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

JSON-RPC #ͱ͸

Slide 10

Slide 10 text

JSON-RPC #ͱ͸ • JSON Λར༻ͨ͠ɺRemote Procedure Call Ͱ͢ɻ • Content-Type: “application/json" • Path: “/jrpc” • Specification ͕ɺ΄΅ϖϥΠν͔͠ͳ͍ɻ • ৽֮͑͘͠Δ͜ͱ͸ɺ΄΅ͳ͍ɻ • http://www.jsonrpc.org/specification 10

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

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 }

Slide 13

Slide 13 text

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 }

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

ඪ४ Package Ͱͷ JSON-RPC

Slide 16

Slide 16 text

ඪ४ Package Ͱͷ JSON-RPC • Go ͸ɺඪ४Ͱ JSON-RPC Λαϙʔτ͍ͯ͠·͢ɻ • import “net/rpc/jsonrpc” • Go BlogͰ΋঺հ͋ΔͷͰׂΓͱ஌͍ͬͯΔਓଟ͍͔΋ • https://blog.golang.org/json-rpc-tale-of-interfaces 16

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

JSON-RPC by net/rpc/jsonrpc • Debug ػೳ΋͍ͭͯΔ 21

Slide 22

Slide 22 text

ݸਓతͳײ૝ • ࣮૷Λ௨ͯ͠ɺ RPC ΛϨΫνϟʔͯ͘͠Ε͍ͯΔɻ • JSON-RPC 2.0 ͷ Spec Λຬ͍ͨͯ͠ͳ͍ɻ • HTTP Ͱड͚औΔ࣌ʹͪΐͬͱख͕͔͔ؒΔɻ • Reflect ͕ɺଟ͍ؾ͕͢Δɻ 22

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

Third Party Package Ͱͷ JSON-RPC

Slide 25

Slide 25 text

Gorilla Toolkit ͷ JSON-RPC • Gorilla Toolkit ͕ɺ Spec Λىͯ͘͜͠Ε͍ͯΔɻ • import “github.com/gorilla/rpc/v2/json2" • Interface ͕ɺѻ͍΍͘͢ͳ͍ͬͯΔɻ 25

Slide 26

Slide 26 text

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 }

Slide 27

Slide 27 text

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 }

Slide 28

Slide 28 text

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 }

Slide 29

Slide 29 text

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 }

Slide 30

Slide 30 text

ݸਓతͳײ૝ • ඪ४ Package Λ౿ऻ͠ɺѻ͍΍͘͢ͳ͍ͬͯΔɻ • Go 1.6 ҎԼͩͱɺ context Λ࣋ͪӡ΂ͳ͍ɻ • ͢͜͠खͷಧ͔ͳ͍෦෼͕͋Δɻ
 ྫʣCustom Error ࣌ͷ Data ͷॻ͖ࠐΊͳ͍౳ 30

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

Φεεϝͷ Package

Slide 33

Slide 33 text

ͳ͍

Slide 34

Slide 34 text

ͷͰɺ࡞Γ·ͨ͠ɻ

Slide 35

Slide 35 text

github.com/osamingo/jsonrpc

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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 }

Slide 39

Slide 39 text

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 }

Slide 40

Slide 40 text

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 }

Slide 41

Slide 41 text

JSON-RPC by osamingo/jsonrpc • MethodRepository ͱ͍͏ܗͰɺmap Λ࢖ͬͯ
 ϝιου໊ͱؔ਺ͷϙΠϯλΛඥ෇͚͍ͯ·͢ɻ • Go ͷόʔδϣϯʹ͔͔ΘΒͣɺcontext ͷ࣋ͪӡͼʹ
 ରԠ͍ͯ͠·͢ɻʢ<3 GAE/SEʣ 41

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

ͱ͸͍͑ • JSON-RPC ͩͱɺSwagger ͱ͔ɺAPI Blueprint ͱ͔
 ࢖͑ͳͯ͘ɺ݁ہίʔυಡΜͰԼ͍͞ͱ͔͠ݴ͑ͳ͍݅ => Debug ػೳ࢖͑͹ JSON Schema ͕ฦͬͯ͘Δɻ 43

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

·ͱΊ

Slide 47

Slide 47 text

·ͱΊ • JSON-RPC ͸ɺεΰ͘؆୯Ͱ͋Δɻ • Go ݴޠ͸ɺඪ४ Package Ͱαϙʔτ͍ͯ͠Δɻ • Gorilla Toolkit ͸ɺJSON-RPC 2.0 Λຬ͍ͨͯ͠Δɻ • osamingo/jsonrpc Λ࢖ͬͯ͘ΕΔͱخ͍͠ɻ
 (awesome-go ʹ΋ొ࿥ࡁΈͩΑɻ)

Slide 48

Slide 48 text

Next xRPC is … ͱ͸͍͑ɺ࣍དྷΔʢདྷ͍ͯΔʣRPC ͸ɺgRPC Ͱ͢ɻ

Slide 49

Slide 49 text

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