Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I set a context value on request for my middleware? Getting go-staticcheck issues

Here’s my ErrorHandler which is a middleware that wraps my other handlers –

func ErrorHandler(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        next.ServeHTTP(w, r)

        if err, ok := r.Context().Value(auth.ErrorContextKey).(error); ok && err != nil {
            switch e := err.(type) {
            case *app.AppError:
                w.WriteHeader(e.Status)
                render.JSON(w, r, e)
                return
            default:
                internalErr := app.NewInternalError("internal-error", "Something went wrong", nil)
                w.WriteHeader(internalErr.Status)
                render.JSON(w, r, internalErr)
                return
            }
        }
    })
}

In my other handlers, I have been trying to add the error to the context, but I get some issues. Here’s an example snippet

func (h *Http) signup(w http.ResponseWriter, r *http.Request) {
    var params dto.SignUpDTO
    decoder := json.NewDecoder(r.Body)
    defer r.Body.Close()
    if err := decoder.Decode(&params); err != nil {
        ctx := context.WithValue(r.Context(), auth.ErrorContextKey, app.NewBadRequestError("auth/invalid-signup-params", "invalid email or password", err))
        r = r.WithContext(ctx)
        return
    }

}

I get an issue on the r = r.WithContext(ctx):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

this value of r is never used (SA4006)go-staticcheck

WithContext doesn’t have side effects and its return value is ignored (SA4017)go-staticcheck

>Solution :

Tried to write a comment but it was too long, so here I go:

About OP’s question if there is a way of doing that in a cleaner way:
The cleaner way is simply don’t do it. Since it’s kind of a bad practice for a method to "know" that there is a decorator/middleware above it.

Instead, you can do a shared method for rendering error

func (h *HTTP) renderError(w http.ResponseWriter, r *http.Request, err error) {
            switch e := err.(type) {
            case *app.AppError:
                w.WriteHeader(e.Status)
                render.JSON(w, r, e)
                return
            default:
                internalErr := app.NewInternalError("internal-error", "Something went wrong", nil)
                w.WriteHeader(internalErr.Status)
                render.JSON(w, r, internalErr)
                return
            }

}

In middleware, you can log/trace/recover from panic/authentication etc, the idea of a middleware is that you add functionality, that the "inner" handler shouldn’t really know or care about. Here your handlers know about the middleware simply because they are doing this line:

ctx := context.WithValue(r.Context(), auth.ErrorContextKey, app.NewBadRequestError("auth/invalid-signup-params", "invalid email or password", err))
r = r.WithContext(ctx)

Instead you can just do:

    if err := decoder.Decode(&params); err != nil {
        h.renderError(w, r, err)
        return
    }
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading