package server import ( "net/http" "net/url" "somehole.com/common/defaults" "somehole.com/common/log" ) type server struct { req Request allowed []string logger log.Logger do func(req Request) (res Response, errRes ErrorResponse) } type Request interface { Parse(*url.Values) error } type Response interface { HttpStatus() int Response() []byte } type ErrorResponse interface { Ok() bool HttpStatus() int ErrorResponse() []byte String() string } func NewServer(req Request, allowed []string, logger log.Logger, do func(req Request) (res Response, errRes ErrorResponse)) *server { return &server{ req: req, allowed: allowed, logger: logger, do: do, } } type defaultError struct { Error string `json:"error"` } func (srv *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !defaults.Empty(srv.req) { w.WriteHeader(http.StatusInternalServerError) w.Write(mustMarshalJson(&defaultError{Error: "internal_server_error"})) srv.logger.Logf(log.LevelError, "expected empty server request template") return } req := srv.req var allowed bool for _, method := range srv.allowed { if method == r.Method { allowed = true break } } if !allowed { w.WriteHeader(http.StatusMethodNotAllowed) w.Write(mustMarshalJson(&defaultError{Error: "method_not_allowed"})) srv.logger.Logf(log.LevelError, "requested method (%s) not one of %v", r.Method, srv.allowed) return } r.ParseForm() req.Parse(&r.Form) res, errRes := srv.do(req) if !errRes.Ok() { w.WriteHeader(errRes.HttpStatus()) w.Write(errRes.ErrorResponse()) srv.logger.Logf(log.LevelError, "request failed: %s", errRes.String()) } w.WriteHeader(res.HttpStatus()) w.Write(res.Response()) }