chore: Update BE http errors to be ui friendly (#1994)

* chore: More UI friendly errors

Mainly capitlization + messages prefix error
This commit is contained in:
Steven Masley
2022-06-03 16:48:09 -05:00
committed by GitHub
parent 847e2b18da
commit c9a4642a12
42 changed files with 544 additions and 317 deletions

View File

@ -65,7 +65,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
}
if cookieValue == "" {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("%q cookie or query parameter must be provided", SessionTokenKey),
Message: fmt.Sprintf("Cookie %q or query parameter must be provided", SessionTokenKey),
})
return
}
@ -73,7 +73,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// APIKeys are formatted: ID-SECRET
if len(parts) != 2 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("invalid %q cookie api key format", SessionTokenKey),
Message: fmt.Sprintf("Invalid %q cookie API key format", SessionTokenKey),
})
return
}
@ -82,13 +82,13 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// Ensuring key lengths are valid.
if len(keyID) != 10 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("invalid %q cookie api key id", SessionTokenKey),
Message: fmt.Sprintf("Invalid %q cookie API key id", SessionTokenKey),
})
return
}
if len(keySecret) != 22 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("invalid %q cookie api key secret", SessionTokenKey),
Message: fmt.Sprintf("Invalid %q cookie API key secret", SessionTokenKey),
})
return
}
@ -96,12 +96,13 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "api key is invalid",
Message: "API key is invalid",
})
return
}
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get api key by id: %s", err.Error()),
Message: "Internal error fetching API key by id",
Detail: err.Error(),
})
return
}
@ -110,7 +111,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// Checking to see if the secret is valid.
if subtle.ConstantTimeCompare(key.HashedSecret, hashed[:]) != 1 {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "api key secret is invalid",
Message: "API key secret is invalid",
})
return
}
@ -127,7 +128,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
oauthConfig = oauth.Github
default:
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("unexpected authentication type %q", key.LoginType),
Message: fmt.Sprintf("Unexpected authentication type %q", key.LoginType),
})
return
}
@ -139,7 +140,8 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
}).Token()
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("couldn't refresh expired oauth token: %s", err.Error()),
Message: "Could not refresh expired Oauth token",
Detail: err.Error(),
})
return
}
@ -154,7 +156,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
// Checking if the key is expired.
if key.ExpiresAt.Before(now) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("api key expired at %q", key.ExpiresAt.String()),
Message: fmt.Sprintf("API key expired at %q", key.ExpiresAt.String()),
})
return
}
@ -182,7 +184,7 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
})
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("api key couldn't update: %s", err.Error()),
Message: fmt.Sprintf("API key couldn't update: %s", err.Error()),
})
return
}
@ -194,14 +196,15 @@ func ExtractAPIKey(db database.Store, oauth *OAuth2Configs) func(http.Handler) h
roles, err := db.GetAuthorizationUserRoles(r.Context(), key.UserID)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "roles not found",
Message: "Internal error fetching user's roles",
Detail: err.Error(),
})
return
}
if roles.Status != database.UserStatusActive {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("user is not active (status = %q), contact an admin to reactivate your account", roles.Status),
Message: fmt.Sprintf("User is not active (status = %q). Contact an admin to reactivate your account.", roles.Status),
})
return
}

View File

@ -15,7 +15,9 @@ func parseUUID(rw http.ResponseWriter, r *http.Request, param string) (uuid.UUID
rawID := chi.URLParam(r, param)
if rawID == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("%q must be provided", param),
Message: "Missing UUID in URL",
// Url params mean nothing to a user
Detail: fmt.Sprintf("%q URL param missing", param),
})
return uuid.UUID{}, false
}
@ -23,7 +25,8 @@ func parseUUID(rw http.ResponseWriter, r *http.Request, param string) (uuid.UUID
parsed, err := uuid.Parse(rawID)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("%q must be a uuid", param),
Message: fmt.Sprintf("Invalid UUID %q", param),
Detail: err.Error(),
})
return uuid.UUID{}, false
}

View File

@ -63,7 +63,8 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
state, err := cryptorand.String(32)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("generate state string: %s", err),
Message: "Internal error generating state string",
Detail: err.Error(),
})
return
}
@ -91,7 +92,7 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
if state == "" {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: "state must be provided",
Message: "State must be provided",
})
return
}
@ -99,13 +100,13 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
stateCookie, err := r.Cookie(oauth2StateCookieName)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("%q cookie must be provided", oauth2StateCookieName),
Message: fmt.Sprintf("Cookie %q must be provided", oauth2StateCookieName),
})
return
}
if stateCookie.Value != state {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "state mismatched",
Message: "State mismatched",
})
return
}
@ -119,7 +120,8 @@ func ExtractOAuth2(config OAuth2Config) func(http.Handler) http.Handler {
oauthToken, err := config.Exchange(r.Context(), code)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("exchange oauth code: %s", err),
Message: "Internal error exchanging Oauth code",
Detail: err.Error(),
})
return
}

View File

@ -46,13 +46,14 @@ func ExtractOrganizationParam(db database.Store) func(http.Handler) http.Handler
organization, err := db.GetOrganizationByID(r.Context(), orgID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("organization %q does not exist", orgID),
Message: fmt.Sprintf("Organization %q does not exist", orgID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get organization: %s", err.Error()),
Message: "Internal error fetching organization",
Detail: err.Error(),
})
return
}
@ -76,13 +77,14 @@ func ExtractOrganizationMemberParam(db database.Store) func(http.Handler) http.H
})
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusForbidden, httpapi.Response{
Message: "not a member of the organization",
Message: "Not a member of the organization",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get organization member: %s", err.Error()),
Message: "Internal error fetching organization member",
Detail: err.Error(),
})
return
}

View File

@ -35,19 +35,20 @@ func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
template, err := db.GetTemplateByID(r.Context(), templateID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("template %q does not exist", templateID),
Message: fmt.Sprintf("Template %q does not exist", templateID),
})
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template: %s", err),
Message: "Internal error fetching template",
Detail: err.Error(),
})
return
}
if template.Deleted {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("template %q does not exist", templateID),
Message: fmt.Sprintf("Template %q does not exist", templateID),
})
return
}

View File

@ -35,13 +35,14 @@ func ExtractTemplateVersionParam(db database.Store) func(http.Handler) http.Hand
templateVersion, err := db.GetTemplateVersionByID(r.Context(), templateVersionID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("template version %q does not exist", templateVersionID),
Message: fmt.Sprintf("Template version %q does not exist", templateVersionID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get template version: %s", err.Error()),
Message: "Internal error fetching template version",
Detail: err.Error(),
})
return
}

View File

@ -2,7 +2,6 @@ package httpmw
import (
"context"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
@ -50,7 +49,8 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
user, err = db.GetUserByID(r.Context(), APIKey(r).UserID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get user: %s", err.Error()),
Message: "Internal error fetching user",
Detail: err.Error(),
})
return
}

View File

@ -31,14 +31,14 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
cookie, err := r.Cookie(SessionTokenKey)
if err != nil {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: fmt.Sprintf("%q cookie must be provided", SessionTokenKey),
Message: fmt.Sprintf("Cookie %q must be provided", SessionTokenKey),
})
return
}
token, err := uuid.Parse(cookie.Value)
if err != nil {
httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{
Message: fmt.Sprintf("parse token %q: %s", cookie.Value, err),
Message: fmt.Sprintf("Parse token %q: %s", cookie.Value, err),
})
return
}
@ -46,14 +46,15 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler {
if errors.Is(err, sql.ErrNoRows) {
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "agent token is invalid",
Message: "Agent token is invalid",
})
return
}
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace agent: %s", err),
Message: "Internal error fetching workspace agent",
Detail: err.Error(),
})
return
}

View File

@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/coder/coder/coderd/database"
@ -33,20 +32,22 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
agent, err := db.GetWorkspaceAgentByID(r.Context(), agentUUID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "agent doesn't exist with that id",
Message: "Agent doesn't exist with that id",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get agent: %s", err),
Message: "Internal error fetching workspace agent",
Detail: err.Error(),
})
return
}
resource, err := db.GetWorkspaceResourceByID(r.Context(), agent.ResourceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get resource: %s", err),
Message: "Internal error fetching workspace resource",
Detail: err.Error(),
})
return
}
@ -54,7 +55,8 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
job, err := db.GetProvisionerJobByID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get job: %s", err),
Message: "Internal error fetching provisioner job",
Detail: err.Error(),
})
return
}
@ -67,14 +69,16 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
build, err := db.GetWorkspaceBuildByJobID(r.Context(), job.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace build: %s", err),
Message: "Internal error fetching workspace build",
Detail: err.Error(),
})
return
}
workspace, err := db.GetWorkspaceByID(r.Context(), build.WorkspaceID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace: %s", err),
Message: "Internal error fetching workspace",
Detail: err.Error(),
})
return
}
@ -82,7 +86,7 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl
apiKey := APIKey(r)
if apiKey.UserID != workspace.OwnerID {
httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{
Message: "getting non-personal agents isn't supported",
Message: "Getting non-personal agents isn't supported",
})
return
}

View File

@ -35,13 +35,14 @@ func ExtractWorkspaceBuildParam(db database.Store) func(http.Handler) http.Handl
workspaceBuild, err := db.GetWorkspaceBuildByID(r.Context(), workspaceBuildID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("workspace build %q does not exist", workspaceBuildID),
Message: fmt.Sprintf("Workspace build %q does not exist", workspaceBuildID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace build: %s", err.Error()),
Message: "Internal error fetching workspace build",
Detail: err.Error(),
})
return
}

View File

@ -33,13 +33,14 @@ func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler {
workspace, err := db.GetWorkspaceByID(r.Context(), workspaceID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("workspace %q does not exist", workspaceID),
Message: fmt.Sprintf("Workspace %q does not exist", workspaceID),
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace: %s", err.Error()),
Message: "Internal error fetching workspace",
Detail: err.Error(),
})
return
}

View File

@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
@ -35,13 +34,14 @@ func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Ha
resource, err := db.GetWorkspaceResourceByID(r.Context(), resourceUUID)
if errors.Is(err, sql.ErrNoRows) {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: "resource doesn't exist with that id",
Message: "Resource doesn't exist with that id",
})
return
}
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner resource: %s", err),
Message: "Internal error fetching provisioner resource",
Detail: err.Error(),
})
return
}
@ -49,7 +49,8 @@ func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Ha
job, err := db.GetProvisionerJobByID(r.Context(), resource.JobID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get provisioner job: %s", err),
Message: "Internal error provisioner job",
Detail: err.Error(),
})
return
}
@ -62,7 +63,8 @@ func ExtractWorkspaceResourceParam(db database.Store) func(http.Handler) http.Ha
build, err := db.GetWorkspaceBuildByJobID(r.Context(), job.ID)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: fmt.Sprintf("get workspace build: %s", err),
Message: "Internal error workspace build",
Detail: err.Error(),
})
return
}