From bfacd19ddcb6293831eaf16e510efc992914a4a0 Mon Sep 17 00:00:00 2001 From: Edwin Date: Sat, 16 Apr 2016 13:30:33 +0800 Subject: [PATCH 1/4] Move msgpack to example --- examples/msgpack/msgpack_entity.go | 42 ++++++++++++++++++++++ examples/msgpack/msgpack_entity_test.go | 46 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 examples/msgpack/msgpack_entity.go create mode 100644 examples/msgpack/msgpack_entity_test.go diff --git a/examples/msgpack/msgpack_entity.go b/examples/msgpack/msgpack_entity.go new file mode 100644 index 00000000..f7746a4f --- /dev/null +++ b/examples/msgpack/msgpack_entity.go @@ -0,0 +1,42 @@ +package restPack + +import ( + restful "github.com/emicklei/go-restful" + "gopkg.in/vmihailenco/msgpack.v2" +) + +const MIME_MSGPACK = "application/x-msgpack" // Accept or Content-Type used in Consumes() and/or Produces() + +// NewEntityAccessorMPack returns a new EntityReaderWriter for accessing MessagePack content. +// This package is not initialized with such an accessor using the MIME_MSGPACK contentType. +func NewEntityAccessorMsgPack(contentType string) restful.EntityReaderWriter { + return entityMsgPackAccess{ContentType: contentType} +} + +// entityOctetAccess is a EntityReaderWriter for Octet encoding +type entityMsgPackAccess struct { + // This is used for setting the Content-Type header when writing + ContentType string +} + +// Read unmarshalls the value from byte slice and using msgpack to unmarshal +func (e entityMsgPackAccess) Read(req *restful.Request, v interface{}) error { + return msgpack.NewDecoder(req.Request.Body).Decode(v) +} + +// Write marshals the value to byte slice and set the Content-Type Header. +func (e entityMsgPackAccess) Write(resp *restful.Response, status int, v interface{}) error { + return writeMsgPack(resp, status, e.ContentType, v) +} + +// writeMsgPack marshals the value to byte slice and set the Content-Type Header. +func writeMsgPack(resp *restful.Response, status int, contentType string, v interface{}) error { + if v == nil { + resp.WriteHeader(status) + // do not write a nil representation + return nil + } + resp.Header().Set(restful.HEADER_ContentType, contentType) + resp.WriteHeader(status) + return msgpack.NewEncoder(resp).Encode(v) +} diff --git a/examples/msgpack/msgpack_entity_test.go b/examples/msgpack/msgpack_entity_test.go new file mode 100644 index 00000000..2ce2dff9 --- /dev/null +++ b/examples/msgpack/msgpack_entity_test.go @@ -0,0 +1,46 @@ +package restPack + +import ( + "bytes" + "net/http" + "net/http/httptest" + "reflect" + "testing" + + restful "github.com/emicklei/go-restful" +) + +func TestMsgPack(t *testing.T) { + + // register msg pack entity + restful.RegisterEntityAccessor(MIME_MSGPACK, NewEntityAccessorMsgPack(MIME_MSGPACK)) + type Tool struct { + Name string + Vendor string + } + + // Write + httpWriter := httptest.NewRecorder() + mpack := &Tool{Name: "json", Vendor: "apple"} + resp := restful.NewResponse(httpWriter) + resp.SetRequestAccepts("application/x-msgpack,*/*;q=0.8") + + err := resp.WriteEntity(mpack) + if err != nil { + t.Errorf("err %v", err) + } + + // Read + bodyReader := bytes.NewReader(httpWriter.Body.Bytes()) + httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) + httpRequest.Header.Set("Content-Type", "application/x-msgpack; charset=UTF-8") + request := restful.NewRequest(httpRequest) + readMsgPack := new(Tool) + err = request.ReadEntity(&readMsgPack) + if err != nil { + t.Errorf("err %v", err) + } + if equal := reflect.DeepEqual(mpack, readMsgPack); !equal { + t.Fatalf("should not be error") + } +} From 7a083f0a8d1b89b6d7c5c4d9eae13facbd12cc5d Mon Sep 17 00:00:00 2001 From: Edwin Date: Sat, 16 Apr 2016 15:31:42 +0800 Subject: [PATCH 2/4] Fix the pr comments --- examples/msgpack/msgpack_entity_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/msgpack/msgpack_entity_test.go b/examples/msgpack/msgpack_entity_test.go index 2ce2dff9..082ca824 100644 --- a/examples/msgpack/msgpack_entity_test.go +++ b/examples/msgpack/msgpack_entity_test.go @@ -33,7 +33,7 @@ func TestMsgPack(t *testing.T) { // Read bodyReader := bytes.NewReader(httpWriter.Body.Bytes()) httpRequest, _ := http.NewRequest("GET", "/test", bodyReader) - httpRequest.Header.Set("Content-Type", "application/x-msgpack; charset=UTF-8") + httpRequest.Header.Set("Content-Type", MIME_MSGPACK) request := restful.NewRequest(httpRequest) readMsgPack := new(Tool) err = request.ReadEntity(&readMsgPack) From af70cbae70a74f6d08582d11ac985077b9fb7e5a Mon Sep 17 00:00:00 2001 From: Edwin Date: Sun, 17 Apr 2016 23:55:47 +0800 Subject: [PATCH 3/4] Remove content-type --- examples/msgpack/msgpack_entity.go | 12 ++---------- examples/msgpack/msgpack_entity_test.go | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/examples/msgpack/msgpack_entity.go b/examples/msgpack/msgpack_entity.go index f7746a4f..330e4589 100644 --- a/examples/msgpack/msgpack_entity.go +++ b/examples/msgpack/msgpack_entity.go @@ -9,14 +9,12 @@ const MIME_MSGPACK = "application/x-msgpack" // Accept or Content-Type used in C // NewEntityAccessorMPack returns a new EntityReaderWriter for accessing MessagePack content. // This package is not initialized with such an accessor using the MIME_MSGPACK contentType. -func NewEntityAccessorMsgPack(contentType string) restful.EntityReaderWriter { - return entityMsgPackAccess{ContentType: contentType} +func NewEntityAccessorMsgPack() restful.EntityReaderWriter { + return entityMsgPackAccess{} } // entityOctetAccess is a EntityReaderWriter for Octet encoding type entityMsgPackAccess struct { - // This is used for setting the Content-Type header when writing - ContentType string } // Read unmarshalls the value from byte slice and using msgpack to unmarshal @@ -26,17 +24,11 @@ func (e entityMsgPackAccess) Read(req *restful.Request, v interface{}) error { // Write marshals the value to byte slice and set the Content-Type Header. func (e entityMsgPackAccess) Write(resp *restful.Response, status int, v interface{}) error { - return writeMsgPack(resp, status, e.ContentType, v) -} - -// writeMsgPack marshals the value to byte slice and set the Content-Type Header. -func writeMsgPack(resp *restful.Response, status int, contentType string, v interface{}) error { if v == nil { resp.WriteHeader(status) // do not write a nil representation return nil } - resp.Header().Set(restful.HEADER_ContentType, contentType) resp.WriteHeader(status) return msgpack.NewEncoder(resp).Encode(v) } diff --git a/examples/msgpack/msgpack_entity_test.go b/examples/msgpack/msgpack_entity_test.go index 082ca824..3f9441fb 100644 --- a/examples/msgpack/msgpack_entity_test.go +++ b/examples/msgpack/msgpack_entity_test.go @@ -13,7 +13,7 @@ import ( func TestMsgPack(t *testing.T) { // register msg pack entity - restful.RegisterEntityAccessor(MIME_MSGPACK, NewEntityAccessorMsgPack(MIME_MSGPACK)) + restful.RegisterEntityAccessor(MIME_MSGPACK, NewEntityAccessorMsgPack()) type Tool struct { Name string Vendor string From 52391b9e70e5f3cb3ce20a27d5083e6cc0dd6da7 Mon Sep 17 00:00:00 2001 From: Edwin Date: Wed, 20 Apr 2016 10:33:06 +0800 Subject: [PATCH 4/4] Add an example to demo how to use --- examples/msgpack/msgpack_entity_test.go | 114 ++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/examples/msgpack/msgpack_entity_test.go b/examples/msgpack/msgpack_entity_test.go index 3f9441fb..9ece3601 100644 --- a/examples/msgpack/msgpack_entity_test.go +++ b/examples/msgpack/msgpack_entity_test.go @@ -2,12 +2,17 @@ package restPack import ( "bytes" + "fmt" + "log" "net/http" "net/http/httptest" "reflect" "testing" + "time" restful "github.com/emicklei/go-restful" + "gopkg.in/vmihailenco/msgpack.v2" + "io/ioutil" ) func TestMsgPack(t *testing.T) { @@ -44,3 +49,112 @@ func TestMsgPack(t *testing.T) { t.Fatalf("should not be error") } } + +func TestWithWebService(t *testing.T) { + serverURL := "http://127.0.0.1:8090" + go func() { + runRestfulMsgPackRouterServer() + }() + if err := waitForServerUp(serverURL); err != nil { + t.Errorf("%v", err) + } + + // send a post request + userData := user{Id: "0001", Name: "Tony"} + msgPackData, err := msgpack.Marshal(userData) + req, err := http.NewRequest("POST", serverURL+"/test/msgpack", bytes.NewBuffer(msgPackData)) + req.Header.Set("Content-Type", MIME_MSGPACK) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + t.Errorf("unexpected error in sending req: %v", err) + } + if resp.StatusCode != http.StatusOK { + t.Errorf("unexpected response: %v, expected: %v", resp.StatusCode, http.StatusOK) + } + + ur := &userResponse{} + expectMsgPackDocument(t, resp, ur) + if ur.Status != statusActive { + t.Fatalf("should not error") + } + log.Printf("user response:%v", ur) +} + +func expectMsgPackDocument(t *testing.T, r *http.Response, doc interface{}) { + data, err := ioutil.ReadAll(r.Body) + defer r.Body.Close() + if err != nil { + t.Error("ExpectMsgPackDocument: unable to read response body :%v", err) + return + } + // put the body back for re-reads + r.Body = ioutil.NopCloser(bytes.NewReader(data)) + + err = msgpack.Unmarshal(data, doc) + if err != nil { + t.Error("ExpectMsgPackDocument: unable to unmarshal MsgPack:%v", err) + } +} + +func runRestfulMsgPackRouterServer() { + + container := restful.NewContainer() + register(container) + + log.Printf("start listening on localhost:8090") + server := &http.Server{Addr: ":8090", Handler: container} + log.Fatal(server.ListenAndServe()) +} + +func waitForServerUp(serverURL string) error { + for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(5 * time.Second) { + _, err := http.Get(serverURL + "/") + if err == nil { + return nil + } + } + return fmt.Errorf("waiting for server timed out") +} + +var ( + statusActive = "active" +) + +type user struct { + Id, Name string +} + +type userResponse struct { + Status string +} + +func register(container *restful.Container) { + restful.RegisterEntityAccessor(MIME_MSGPACK, NewEntityAccessorMsgPack()) + ws := new(restful.WebService) + ws. + Path("/test"). + Consumes(restful.MIME_JSON, MIME_MSGPACK). + Produces(restful.MIME_JSON, MIME_MSGPACK) + // route user api + ws.Route(ws.POST("/msgpack"). + To(do). + Reads(user{}). + Writes(userResponse{})) + container.Add(ws) +} + +func do(request *restful.Request, response *restful.Response) { + u := &user{} + err := request.ReadEntity(u) + if err != nil { + log.Printf("should be no error, got:%v", err) + } + log.Printf("got:%v", u) + + ur := &userResponse{Status: statusActive} + + response.SetRequestAccepts(MIME_MSGPACK) + response.WriteEntity(ur) +}