为了账号安全,请及时绑定邮箱和手机立即绑定

总是尝试返回相同的响应结构时,如何最小化 Go Mux 中的重复代码?

总是尝试返回相同的响应结构时,如何最小化 Go Mux 中的重复代码?

Go
万千封印 2023-01-03 11:30:28
我有大量类似于以下代码片段的代码,我只是尝试填充我的响应结构、json 编组输出、设置状态代码并返回结果:if err := json.NewDecoder(r.Body).Decode(&user); err != nil {            response := responses.UserResponse{                Status:  http.StatusBadRequest,                Message: "error",                Data:    map[string]interface{}{"error": err.Error()},            }            rw.WriteHeader(http.StatusBadRequest)            errRes, _ := json.Marshal(response)            rw.Write(errRes)            return        }我试图创建一个接收r变量(request.http)的函数来接收正文以及响应的状态代码。但注意到我必须再次检查函数外部的错误代码,然后再次执行相同的响应创建流程。Go 专家如何尽量减少像这样的代码重复?首先有这样的代码重复可以吗?
查看完整描述

2 回答

?
慕村225694

TA贡献1880条经验 获得超4个赞

通过将解码调用和错误处理移至可重用函数来最大程度地减少代码重复:


// Decode returns true if the request body is successfully decoded

// to the value pointed to by pv. Otherwise, decode writes an error

// response and returns false.

func decode(rw http.ResponseWriter, r *http.Request, pv interface{}) bool {

    err := json.NewDecoder(r.Body).Decode(pv)

    if err == nil {

        return true

    }

    rw.WriteHeader(http.StatusBadRequest)

    json.NewEncoder(rw).Encode(map[string]any{

        "status":  http.StatusBadRequest,

        "message": "error",

        "data":    map[string]any{"error": err.Error()},

    })

    return false

}

使用这样的功能:


func userHandler(rw http.ResponseWriter, r *http.Request) {

    var u UserRequest

    if !decode(rw, r, &u) {

        return

    }

}


查看完整回答
反对 回复 2023-01-03
?
红颜莎娜

TA贡献1842条经验 获得超12个赞

最好抽象细节以提供有关您的处理程序所做工作的高级图片。


func (h *rideHandler) handleCancelRideByPassenger(w http.ResponseWriter, r *http.Request) {


    ctx := r.Context()


    user := getUser(ctx)


    req := &cancelRequest{}


    if err := decode(r, req); err != nil {

        h.logger.Error("cancel ride: problem while decoding body request", zap.String("ip", r.RemoteAddr), zap.Error(err))

        h.respond.BadRequest(w, NewRESTError(reasonDecoding, "problem while decoding input parameters"))

        return

    }

    req.PublicID = chi.URLParam(r, "id")


    err := h.rideService.CancelRide(ctx, req, user)

    if err != nil {

        var validationErr *ValidationError

        switch {

        case errors.As(err, &validationErr):

            h.respond.BadRequest(w, NewRESTValidationError(reasonValidation, "problem while validating request", validationErr))

            return

        default:

            h.respond.InternalServerError(w, NewRESTError(reasonInternalError, "unknown problem occurred"))

            return

        }

    }


    h.respond.Ok(w, NewRESTResponse(&cancelRideResponse{Success: true}))


}

处理程序利用一些方便的糖函数来删除重复,并提供处理程序的高级概述而不是底层细节。


func decode(request *http.Request, val interface{}) error {

    dec := json.NewDecoder(request.Body)

    dec.DisallowUnknownFields()

    return dec.Decode(val)

}


type Responder struct {

    Encoder Encoder

    Before BeforeFunc

    After AfterFunc

    OnError OnErrorFunc

}


func (r *Responder) writeResponse(w http.ResponseWriter, v interface{}, status int) {


    if r.Before != nil {

        status, v = r.Before(w, v, status)

    }


    encoder := JSON

    if r.Encoder != nil {

        encoder = r.Encoder

    }


    w.Header().Set("Content-Type", encoder.ContentType())

    w.WriteHeader(status)

    if err := encoder.Encode(w, v); err != nil {

        if r.OnError != nil {

            r.OnError(err)

        }

    }


    if r.After != nil {

        r.After(v, status)

    }


}


func (r *Responder) Ok(w http.ResponseWriter, v interface{}) {

    r.writeResponse(w, v, http.StatusOK)

}

可能您应该编写自己的响应包或检查开源中的可用内容。然后你就可以在任何地方使用这个具有相同响应结构的响应包。


查看完整回答
反对 回复 2023-01-03
  • 2 回答
  • 0 关注
  • 62 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信