Skip to content

Commit

Permalink
feat: supports adding page info to http response
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhengYa-0110 committed Jan 17, 2025
1 parent b7ef92e commit 722a36f
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 30 deletions.
2 changes: 1 addition & 1 deletion server/controller/http/router/common/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/op/go-logging"
)

var log = logging.MustGetLogger("common/controller")
var log = logging.MustGetLogger("http.router.common")

func ForwardMasterController(c *gin.Context, masterControllerName string, port int) {
requestHosts := strings.Split(c.Request.Host, ":")
Expand Down
103 changes: 75 additions & 28 deletions server/controller/http/router/common/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package common

import (
"encoding/json"
"errors"
"fmt"
"net/http"
Expand All @@ -31,14 +32,59 @@ type Response struct {
OptStatus string `json:"OPT_STATUS"`
Description string `json:"DESCRIPTION"`
Data interface{} `json:"DATA"`
Page Page `json:"PAGE"`
}

func HttpResponse(c *gin.Context, httpCode int, data interface{}, optStatus string, description string) {
c.JSON(httpCode, Response{
OptStatus: optStatus,
Description: description,
Data: data,
})
// String returns the string representation of the response when Data is a byte slice.
func (r Response) String() string {
return fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s,"PAGE":%s}`, r.OptStatus, r.Description, string(r.Data.([]byte)), r.Page.String())
}

// Bytes returns the byte slice representation of the response when Data is a byte slice.
func (r Response) Bytes() []byte {
return []byte(r.String())
}

type Page struct {
Index int `json:"INDEX"`
Size int `json:"SIZE"`
Total int `json:"TOTAL"`
TotalItem int `json:"TOTAL_ITEM"`
}

func (p Page) String() string {
bytes, _ := json.Marshal(p)
return string(bytes)
}

type ResponseOption func(resp *Response)

func WithPage(p Page) ResponseOption {
log.Infof("ResponseOption resp: %#v", p)
return func(resp *Response) {
resp.Page = p
}
}

func WithDescription(description string) ResponseOption {
return func(resp *Response) {
resp.Description = description
}
}

func HttpResponse(c *gin.Context, httpCode int, data interface{}, optStatus string, options ...ResponseOption) {
resp := Response{
OptStatus: optStatus,
Data: data,
}
for _, option := range options {
option(&resp)
log.Infof("ResponseOption option: %#v", option)
log.Infof("ResponseOption resp: %#v", resp)
}
log.Infof("ResponseOption option: %#v", options)
log.Infof("ResponseOption resp: %#v", resp)
c.JSON(httpCode, resp)
}

func BadRequestResponse(c *gin.Context, optStatus string, description string) {
Expand Down Expand Up @@ -79,9 +125,10 @@ func StatusForbiddenResponse(c *gin.Context, description string) {
})
}

func JsonResponse(c *gin.Context, data interface{}, err error) {
// TODO refactor, use ResponseOption
func JsonResponse(c *gin.Context, data interface{}, err error, respOptions ...ResponseOption) {
if _, ok := data.([]byte); ok {
bytesResponse(c, data, err)
bytesResponse(c, data, err, respOptions...)
return
}

Expand Down Expand Up @@ -110,47 +157,47 @@ func JsonResponse(c *gin.Context, data interface{}, err error) {
InternalErrorResponse(c, data, httpcommon.FAIL, err.Error())
}
} else {
HttpResponse(c, 200, data, httpcommon.SUCCESS, "")
HttpResponse(c, 200, data, httpcommon.SUCCESS, respOptions...)
}
}

func bytesResponse(c *gin.Context, data interface{}, err error) {
func bytesResponse(c *gin.Context, data interface{}, err error, respOptions ...ResponseOption) {
resp := Response{Data: data}
for _, opt := range respOptions {
opt(&resp)
}
if err != nil {
switch t := err.(type) {
case *servicecommon.ServiceError:
resp.OptStatus = t.Status
resp.Description = t.Message
switch t.Status {
case httpcommon.NO_PERMISSIONS:
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusForbidden, gin.MIMEJSON, []byte(d))
c.Data(http.StatusForbidden, gin.MIMEJSON, resp.Bytes())
case httpcommon.RESOURCE_NOT_FOUND, httpcommon.INVALID_POST_DATA, httpcommon.RESOURCE_NUM_EXCEEDED,
httpcommon.SELECTED_RESOURCES_NUM_EXCEEDED, httpcommon.RESOURCE_ALREADY_EXIST,
httpcommon.PARAMETER_ILLEGAL, httpcommon.INVALID_PARAMETERS:
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusBadRequest, gin.MIMEJSON, []byte(d))
c.Data(http.StatusBadRequest, gin.MIMEJSON, resp.Bytes())
case httpcommon.SERVER_ERROR, httpcommon.CONFIG_PENDING:
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusInternalServerError, gin.MIMEJSON, []byte(d))
c.Data(http.StatusInternalServerError, gin.MIMEJSON, resp.Bytes())
case httpcommon.SERVICE_UNAVAILABLE:
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusServiceUnavailable, gin.MIMEJSON, []byte(d))
c.Data(http.StatusServiceUnavailable, gin.MIMEJSON, resp.Bytes())
case httpcommon.STATUES_PARTIAL_CONTENT:
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusPartialContent, gin.MIMEJSON, []byte(d))
c.Data(http.StatusPartialContent, gin.MIMEJSON, resp.Bytes())
default:
if errors.Is(err, httpcommon.ERR_NO_PERMISSIONS) {
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusForbidden, gin.MIMEJSON, []byte(d))
c.Data(http.StatusForbidden, gin.MIMEJSON, resp.Bytes())
return
}
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, t.Status, t.Message, string(data.([]byte)))
c.Data(http.StatusBadRequest, gin.MIMEJSON, []byte(d))
c.Data(http.StatusBadRequest, gin.MIMEJSON, resp.Bytes())
}
default:
d := fmt.Sprintf(`{"OPT_STATUS":%s,"DESCRIPTION":%s,"DATA":%s}`, httpcommon.FAIL, err.Error(), string(data.([]byte)))
c.Data(http.StatusInternalServerError, gin.MIMEJSON, []byte(d))
resp.OptStatus = httpcommon.FAIL
resp.Description = err.Error()
c.Data(http.StatusInternalServerError, gin.MIMEJSON, resp.Bytes())
}
} else {
d := fmt.Sprintf(`{"OPT_STATUS":"SUCCESS","DESCRIPTION":"","DATA": %v}`, string(data.([]byte)))
c.Data(http.StatusOK, gin.MIMEJSON, []byte(d))
resp.OptStatus = httpcommon.SUCCESS
c.Data(http.StatusOK, gin.MIMEJSON, resp.Bytes())
}
}
63 changes: 63 additions & 0 deletions server/controller/http/router/common/response_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Yunshan Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package common

import (
"fmt"
"net/http/httptest"
"testing"

"github.com/gin-gonic/gin"
)

func TestHttpResponse(t *testing.T) {
gin.SetMode(gin.TestMode)
type args struct {
c *gin.Context
code int
status string
data interface{}
opts []ResponseOption
}
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
tests := []struct {
name string
args args
}{
{
name: "TestHttpResponse",
args: args{
c: c,
code: 200,
status: "success",
data: nil,
opts: []ResponseOption{WithPage(Page{Index: 1, Size: 10, Total: 1, TotalItem: 1})},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
HttpResponse(tt.args.c, tt.args.code, tt.args.data, tt.args.status, tt.args.opts...)
})
// check response
if w.Code != tt.args.code {
t.Errorf("HttpResponse() code = %d, want %d", w.Code, tt.args.code)
}
fmt.Println(w.Body.String())
}
}
2 changes: 1 addition & 1 deletion server/controller/http/router/resource/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func getDomains(cfg *config.ControllerConfig) gin.HandlerFunc {
excludeTeamIDs = append(excludeTeamIDs, k)
}
data, err := resource.GetDomains(db, excludeTeamIDs, args)
common.JsonResponse(c, data, err)
common.JsonResponse(c, data, err, common.WithPage(common.Page{Index: 1, Size: 10}))
})
}

Expand Down

0 comments on commit 722a36f

Please sign in to comment.