Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize errors #359

Merged
merged 6 commits into from
Feb 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
/event-gateway
vendor
*.swp
Expand Down
10 changes: 5 additions & 5 deletions functions/httpapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (h HTTPAPI) getFunction(w http.ResponseWriter, r *http.Request, params http
w.WriteHeader(http.StatusInternalServerError)
}

encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
} else {
encoder.Encode(fn)
}
Expand All @@ -47,7 +47,7 @@ func (h HTTPAPI) getFunctions(w http.ResponseWriter, r *http.Request, params htt
fns, err := h.Functions.GetAllFunctions()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
} else {
encoder.Encode(&functions{fns})
}
Expand Down Expand Up @@ -80,7 +80,7 @@ func (h HTTPAPI) registerFunction(w http.ResponseWriter, r *http.Request, params
w.WriteHeader(http.StatusInternalServerError)
}

encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand Down Expand Up @@ -111,7 +111,7 @@ func (h HTTPAPI) updateFunction(w http.ResponseWriter, r *http.Request, params h
w.WriteHeader(http.StatusInternalServerError)
}

encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand All @@ -130,7 +130,7 @@ func (h HTTPAPI) deleteFunction(w http.ResponseWriter, r *http.Request, params h
w.WriteHeader(http.StatusInternalServerError)
}

encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
} else {
w.WriteHeader(http.StatusNoContent)
}
Expand Down
6 changes: 5 additions & 1 deletion internal/httpapi/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package httpapi

import "fmt"

type Response struct {
Errors []Error `json:"errors"`
}

// Error represents generic HTTP error returned by Configuration API.
type Error struct {
Error string `json:"error"`
Message string `json:"message"`
}

// ErrMalformedJSON occurring when it's impossible to decode JSON payload.
Expand Down
48 changes: 36 additions & 12 deletions router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package router
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"regexp"
Expand All @@ -17,6 +16,7 @@ import (
eventpkg "github.com/serverless/event-gateway/event"
"github.com/serverless/event-gateway/functions"
"github.com/serverless/event-gateway/plugin"
"github.com/serverless/event-gateway/internal/httpapi"
)

// Router calls a target function when an endpoint is hit, and handles pubsub message delivery.
Expand Down Expand Up @@ -47,9 +47,12 @@ func New(workersNumber uint, backlogLength uint, targetCache Targeter, plugins *
}

func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
encoder := json.NewEncoder(w)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

content type should be set here.

// if we're draining requests, spit back a 503
if router.isDraining() {
http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
w.WriteHeader(http.StatusServiceUnavailable)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: http.StatusText(http.StatusServiceUnavailable) }}})
return
}

Expand All @@ -60,7 +63,9 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {

event, _, err := router.eventFromRequest(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand All @@ -69,13 +74,16 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cors.AllowAll().ServeHTTP(w, r, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, "custom event can be emitted only with POST method")
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: "custom event can be emitted only with POST method" }}})
return
}

event, path, err := router.eventFromRequest(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand Down Expand Up @@ -242,6 +250,7 @@ func (router *Router) eventFromRequest(r *http.Request) (*eventpkg.Event, string
return event, path, nil
}
func (router *Router) handleHTTPEvent(event *eventpkg.Event, w http.ResponseWriter, r *http.Request) {
encoder := json.NewEncoder(w)
reqMethod := r.Method

// check if CORS pre-flight request
Expand All @@ -253,7 +262,9 @@ func (router *Router) handleHTTPEvent(event *eventpkg.Event, w http.ResponseWrit
)
if backingFunction == nil {
router.log.Debug("Function not found for HTTP event.", zap.Object("event", event))
http.Error(w, "resource not found", http.StatusNotFound)
w.WriteHeader(http.StatusNotFound)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: "resource not found" }}})
return
}

Expand All @@ -263,15 +274,19 @@ func (router *Router) handleHTTPEvent(event *eventpkg.Event, w http.ResponseWrit
event.Data = httpdata
resp, err := router.callFunction(*backingFunction, *event)
if err != nil {
http.Error(w, "function call failed", http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: "function call failed" }}})
return
}

httpResponse := &HTTPResponse{StatusCode: http.StatusOK}
err = json.Unmarshal(resp, httpResponse)
if err != nil {
router.log.Info("HTTP response object malformed.", zap.String("response", string(resp)))
http.Error(w, "HTTP response object malformed", http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: "HTTP response object malformed" }}})
return
}

Expand All @@ -283,7 +298,9 @@ func (router *Router) handleHTTPEvent(event *eventpkg.Event, w http.ResponseWrit

_, err = w.Write(resp)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand All @@ -306,23 +323,30 @@ func (router *Router) handleHTTPEvent(event *eventpkg.Event, w http.ResponseWrit
}

func (router *Router) handleInvokeEvent(path string, event *eventpkg.Event, w http.ResponseWriter, r *http.Request) {
encoder := json.NewEncoder(w)
routerEventsSyncReceived.Inc()

functionID := functions.FunctionID(r.Header.Get(headerFunctionID))
if !router.targetCache.InvokableFunction(path, functionID) {
http.Error(w, "function or subscription not found", http.StatusNotFound)
w.WriteHeader(http.StatusNotFound)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: "function or subscription not found" }}})
return
}

resp, err := router.callFunction(functionID, *event)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

_, err = w.Write(resp)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("content-type", "application/json")
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand Down
6 changes: 3 additions & 3 deletions subscriptions/httpapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (h HTTPAPI) createSubscription(w http.ResponseWriter, r *http.Request, para
w.WriteHeader(http.StatusInternalServerError)
}

encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
return
}

Expand All @@ -70,7 +70,7 @@ func (h HTTPAPI) deleteSubscription(w http.ResponseWriter, r *http.Request, para
} else {
w.WriteHeader(http.StatusInternalServerError)
}
encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
} else {
w.WriteHeader(http.StatusNoContent)
}
Expand All @@ -83,7 +83,7 @@ func (h HTTPAPI) getSubscriptions(w http.ResponseWriter, r *http.Request, params
subs, err := h.Subscriptions.GetAllSubscriptions()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
encoder.Encode(&httpapi.Error{Error: err.Error()})
encoder.Encode(&httpapi.Response{Errors: []httpapi.Error{{ Message: err.Error() }}})
} else {
encoder.Encode(&subscriptions{subs})
}
Expand Down