0

What I want to achieve here is to create a very generic middleware called, Expects that actually validates the current request according to the parameters provided. It will raise a Bad Request if the required params are not present or are empty. In Python (Flask) this would be very simple like:

@app.route('/endpoint', methods=['POST'])
@expects(['param1', 'param2'])
def endpoint_handler():
    return 'Hello World'

The definition of expects would look like this (a very minimal example):

def expects(fields):
    def decorator(view_function):

        @wraps(view_function)
        def wrapper(*args, **kwargs):
            # get current request data
            data = request.get_json(silent=True) or {}          

            for f in fields:
                if f not in data.keys():
                    raise Exception("Bad Request")

            return view_function(*args, **kwargs)

        return wrapper
    return decorator

I am just confused a little about how would I achieve that in Go. What I tried so far is:

type RequestParam interface {
    Validate() (bool, error)
}

type EndpointParamsRequired struct {
    SomeParam string `json:"some_param"`
}

func (p *EndpointParamsRequired) Validate() {
    // My validation logic goes here
    if len(p.SomeParam) == 0 {
        return false, "Missing field"
    }
}

func Expects(p RequestParam, h http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Check if present in JSON request

        // Unmarshall JSON
        ...

        if _, err := p.Validate(); err != nil {
            w.WriteHeader(http.StatusBadRequest)
            fmt.Fprintf(w, "Bad request: %s", err)

            return
        }
    }
}

and from main.go file:

func main() {
    var (
        endopintParams EndpointParamsRequired
    )

    r.HandleFunc("/endpoint", Expects(&endopintParams, EndpointHandler)).Methods("POST")

}

It actually works for the first time and validates the request, but after one valid request all the consecutive requests are successful even if the json does not contain the required param. Does that have anything to do with the global endopintParams I'm creating?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Ahmed Dhanani
  • 841
  • 1
  • 11
  • 32
  • 1
    *"Does that have anything to do with the global endopintParams i'm creating?"* Yes, since you're passing the address of `endpointParams`, `p` will always point to the same place in memory. That means that each time the handler+middleware is executed they are dealing with the *same* instance, unmarshaling json into the same block of memory, etc. – mkopriva Mar 16 '19 at 14:07
  • @mkopriva what would be the best way to reinitialize the `endpointParams` – Ahmed Dhanani Mar 16 '19 at 16:09
  • 1
    Well, the best advise is to start in a _non_ _generic_ way. – Volker Mar 16 '19 at 16:41

0 Answers0