Skip to content

Commit 044566d

Browse files
committed
Rework APIs to use Go error
1 parent a75361d commit 044566d

File tree

12 files changed

+184
-144
lines changed

12 files changed

+184
-144
lines changed

api/ban.go

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,17 @@ import (
1515

1616
func HandleBan(w http.ResponseWriter, r *http.Request) {
1717
var user *database.User
18-
var success bool
19-
var err string
2018
var statusCode int
19+
var err error
2120

2221
if r.Method == http.MethodPost {
23-
user, success, err, statusCode = handleBanImpl(r)
22+
user, statusCode, err = handleBanImpl(r)
2423
} else if r.Method == http.MethodOptions {
2524
statusCode = http.StatusNoContent
2625
w.Header().Set("Access-Control-Allow-Methods", "POST")
2726
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
2827
} else {
29-
err = "Incorrect request. POST only."
28+
err = ErrPostOnly
3029
statusCode = http.StatusMethodNotAllowed
3130
w.Header().Set("Allow", "POST")
3231
}
@@ -41,7 +40,7 @@ func HandleBan(w http.ResponseWriter, r *http.Request) {
4140

4241
if statusCode != http.StatusNoContent {
4342
w.Header().Set("Content-Type", "application/json")
44-
jsonData, _ = json.Marshal(UserActionResponse{*user, success, err})
43+
jsonData, _ = json.Marshal(UserActionResponse{*user, err == nil, resolveError(err)})
4544
}
4645

4746
w.Header().Set("Content-Length", strconv.Itoa(len(jsonData)))
@@ -61,30 +60,30 @@ type BanRequestSpec struct {
6160
Moderator string `json:"moderator"`
6261
}
6362

64-
func handleBanImpl(r *http.Request) (*database.User, bool, string, int) {
63+
func handleBanImpl(r *http.Request) (*database.User, int, error) {
6564
// TODO: Actual authentication rather than a fixed secret
6665

6766
body, err := io.ReadAll(r.Body)
6867
if err != nil {
69-
return nil, false, "Unable to read request body", http.StatusBadRequest
68+
return nil, http.StatusBadRequest, ErrRequestBody
7069
}
7170

7271
var req BanRequestSpec
7372
err = json.Unmarshal(body, &req)
7473
if err != nil {
75-
return nil, false, err.Error(), http.StatusBadRequest
74+
return nil, http.StatusBadRequest, err
7675
}
7776

7877
if apiSecret == "" || req.Secret != apiSecret {
79-
return nil, false, "Invalid API secret in request", http.StatusUnauthorized
78+
return nil, http.StatusUnauthorized, ErrInvalidSecret
8079
}
8180

8281
if req.ProfileID == 0 {
83-
return nil, false, "Profile ID missing or 0 in request", http.StatusBadRequest
82+
return nil, http.StatusBadRequest, ErrPIDMissing
8483
}
8584

8685
if req.Reason == "" {
87-
return nil, false, "Missing ban reason in request", http.StatusBadRequest
86+
return nil, http.StatusBadRequest, ErrReason
8887
}
8988

9089
moderator := req.Moderator
@@ -94,27 +93,24 @@ func handleBanImpl(r *http.Request) (*database.User, bool, string, int) {
9493

9594
minutes := req.Days*24*60 + req.Hours*60 + req.Minutes
9695
if minutes == 0 {
97-
return nil, false, "Ban length missing or 0", http.StatusBadRequest
96+
return nil, http.StatusBadRequest, ErrLength
9897
}
9998

10099
length := time.Duration(minutes) * time.Minute
101100

102101
logging.Notice("API:"+moderator, "Ban profile:", aurora.Cyan(req.ProfileID), "TOS:", aurora.Cyan(req.Tos), "Length:", aurora.Cyan(length), "Reason:", aurora.BrightCyan(req.Reason), "Reason (Hidden):", aurora.BrightCyan(req.ReasonHidden))
103102

104103
if !database.BanUser(pool, ctx, req.ProfileID, req.Tos, length, req.Reason, req.ReasonHidden, moderator) {
105-
return nil, false, "Failed to ban user", http.StatusInternalServerError
104+
return nil, http.StatusInternalServerError, ErrTransaction
106105
}
107106

108107
gpcm.KickPlayerCustomMessage(req.ProfileID, req.Reason, gpcm.WWFCMsgProfileRestrictedCustom)
109108

110-
var message string
111109
user, success := database.GetProfile(pool, ctx, req.ProfileID)
112110

113-
if success {
114-
message = ""
115-
} else {
116-
message = "Unable to query user data from the database"
111+
if !success {
112+
return nil, http.StatusInternalServerError, ErrUserQueryTransaction
117113
}
118114

119-
return &user, success, message, http.StatusOK
115+
return &user, http.StatusOK, nil
120116
}

api/clear.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ import (
1010

1111
func HandleClear(w http.ResponseWriter, r *http.Request) {
1212
var user *database.User
13-
var success bool
14-
var err string
1513
var statusCode int
14+
var err error
1615

1716
if r.Method == http.MethodPost {
18-
user, success, err, statusCode = handleClearImpl(r)
17+
user, statusCode, err = handleClearImpl(r)
1918
} else if r.Method == http.MethodOptions {
2019
statusCode = http.StatusNoContent
2120
w.Header().Set("Access-Control-Allow-Methods", "POST")
2221
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
2322
} else {
24-
err = "Incorrect request. POST only."
23+
err = ErrPostOnly
2524
statusCode = http.StatusMethodNotAllowed
2625
w.Header().Set("Allow", "POST")
2726
}
@@ -36,7 +35,7 @@ func HandleClear(w http.ResponseWriter, r *http.Request) {
3635

3736
if statusCode != http.StatusNoContent {
3837
w.Header().Set("Content-Type", "application/json")
39-
jsonData, _ = json.Marshal(UserActionResponse{*user, success, err})
38+
jsonData, _ = json.Marshal(UserActionResponse{*user, err == nil, resolveError(err)})
4039
}
4140

4241
w.Header().Set("Content-Length", strconv.Itoa(len(jsonData)))
@@ -49,30 +48,29 @@ type ClearRequestSpec struct {
4948
ProfileID uint32 `json:"pid"`
5049
}
5150

52-
func handleClearImpl(r *http.Request) (*database.User, bool, string, int) {
51+
func handleClearImpl(r *http.Request) (*database.User, int, error) {
5352
// TODO: Actual authentication rather than a fixed secret
5453

5554
body, err := io.ReadAll(r.Body)
5655
if err != nil {
57-
return nil, false, "Unable to read request body", http.StatusBadRequest
56+
return nil, http.StatusBadRequest, ErrRequestBody
5857
}
5958

6059
var req ClearRequestSpec
6160
err = json.Unmarshal(body, &req)
6261
if err != nil {
63-
return nil, false, err.Error(), http.StatusBadRequest
62+
return nil, http.StatusBadRequest, err
6463
}
6564

6665
if apiSecret == "" || req.Secret != apiSecret {
67-
return nil, false, "Invalid API secret in request", http.StatusUnauthorized
66+
return nil, http.StatusUnauthorized, ErrInvalidSecret
6867
}
6968

7069
user, success := database.ClearProfile(pool, ctx, req.ProfileID)
7170

7271
if !success {
73-
return nil, false, "Unable to query user data from the database", http.StatusInternalServerError
72+
return nil, http.StatusInternalServerError, ErrTransaction
7473
}
7574

76-
// Don't return empty JSON, this is placeholder for now.
77-
return &user, true, "", http.StatusOK
75+
return &user, http.StatusOK, nil
7876
}

api/common.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package api
2+
3+
import (
4+
"errors"
5+
"wwfc/database"
6+
)
7+
8+
var (
9+
ErrPostOnly = errors.New("Incorrect request. POST only.")
10+
ErrGetOnly = errors.New("Incorrect request. GET only.")
11+
ErrPostGetOnly = errors.New("Incorrect request. POST and GET only.")
12+
ErrRequestBody = errors.New("Unable to read request body")
13+
ErrInvalidSecret = errors.New("Invalid API secret in request")
14+
ErrPIDMissing = errors.New("Profile ID missing or 0 in request")
15+
ErrReason = errors.New("Missing reason in request")
16+
ErrLength = errors.New("Ban length missing or 0")
17+
ErrTransaction = errors.New("Failed to complete database transaction")
18+
ErrUserQuery = errors.New("Failed to find user in the database")
19+
ErrUserQueryTransaction = errors.New("Failed to find user in the database, but the intended transaction may have gone through")
20+
)
21+
22+
func resolveError(err error) string {
23+
if err != nil {
24+
return err.Error()
25+
}
26+
27+
return ""
28+
}
29+
30+
type UserActionResponse struct {
31+
User database.User
32+
Success bool
33+
Error string
34+
}

api/get_hash.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@ import (
1010

1111
func HandleGetHash(w http.ResponseWriter, r *http.Request) {
1212
var store database.HashStore
13-
var success bool
14-
var err string
1513
var statusCode int
14+
var err error
1615

1716
if r.Method == http.MethodPost {
18-
store, success, err, statusCode = handleGetHashImpl(r)
17+
store, statusCode, err = handleGetHashImpl(r)
1918
} else if r.Method == http.MethodOptions {
2019
statusCode = http.StatusNoContent
2120
w.Header().Set("Access-Control-Allow-Methods", "POST")
2221
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
2322
} else {
24-
err = "Incorrect request. POST only."
23+
err = ErrPostOnly
2524
statusCode = http.StatusMethodNotAllowed
2625
w.Header().Set("Allow", "POST")
2726
}
@@ -32,7 +31,7 @@ func HandleGetHash(w http.ResponseWriter, r *http.Request) {
3231

3332
if statusCode != http.StatusNoContent {
3433
w.Header().Set("Content-Type", "application/json")
35-
jsonData, _ = json.Marshal(GetHashResponse{success, err, store})
34+
jsonData, _ = json.Marshal(GetHashResponse{err == nil, resolveError(err), store})
3635
}
3736

3837
w.Header().Set("Content-Length", strconv.Itoa(len(jsonData)))
@@ -50,23 +49,21 @@ type GetHashResponse struct {
5049
Hashes database.HashStore
5150
}
5251

53-
func handleGetHashImpl(r *http.Request) (database.HashStore, bool, string, int) {
54-
ret := database.HashStore{}
55-
52+
func handleGetHashImpl(r *http.Request) (database.HashStore, int, error) {
5653
body, err := io.ReadAll(r.Body)
5754
if err != nil {
58-
return ret, false, "Unable to read request body", http.StatusBadRequest
55+
return nil, http.StatusBadRequest, ErrRequestBody
5956
}
6057

6158
var req GetHashRequestSpec
6259
err = json.Unmarshal(body, &req)
6360
if err != nil {
64-
return ret, false, err.Error(), http.StatusBadRequest
61+
return nil, http.StatusBadRequest, err
6562
}
6663

6764
if apiSecret == "" || req.Secret != apiSecret {
68-
return nil, false, "Invalid API secret in request", http.StatusUnauthorized
65+
return nil, http.StatusUnauthorized, ErrInvalidSecret
6966
}
7067

71-
return database.GetHashes(), true, "", http.StatusOK
68+
return database.GetHashes(), http.StatusOK, nil
7269
}

api/kick.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,17 @@ import (
1111

1212
func HandleKick(w http.ResponseWriter, r *http.Request) {
1313
var user *database.User
14-
var success bool
15-
var err string
1614
var statusCode int
15+
var err error
1716

1817
if r.Method == http.MethodPost {
19-
user, success, err, statusCode = handleKickImpl(r)
18+
user, statusCode, err = handleKickImpl(r)
2019
} else if r.Method == http.MethodOptions {
2120
statusCode = http.StatusNoContent
2221
w.Header().Set("Access-Control-Allow-Methods", "POST")
2322
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
2423
} else {
25-
err = "Incorrect request. POST only."
24+
err = ErrPostOnly
2625
statusCode = http.StatusMethodNotAllowed
2726
w.Header().Set("Allow", "POST")
2827
}
@@ -37,7 +36,7 @@ func HandleKick(w http.ResponseWriter, r *http.Request) {
3736

3837
if statusCode != http.StatusNoContent {
3938
w.Header().Set("Content-Type", "application/json")
40-
jsonData, _ = json.Marshal(UserActionResponse{*user, success, err})
39+
jsonData, _ = json.Marshal(UserActionResponse{*user, err == nil, resolveError(err)})
4140
}
4241

4342
w.Header().Set("Content-Length", strconv.Itoa(len(jsonData)))
@@ -51,42 +50,39 @@ type KickRequestSpec struct {
5150
ProfileID uint32 `json:"pid"`
5251
}
5352

54-
func handleKickImpl(r *http.Request) (*database.User, bool, string, int) {
53+
func handleKickImpl(r *http.Request) (*database.User, int, error) {
5554
// TODO: Actual authentication rather than a fixed secret
5655

5756
body, err := io.ReadAll(r.Body)
5857
if err != nil {
59-
return nil, false, "Unable to read request body", http.StatusBadRequest
58+
return nil, http.StatusBadRequest, ErrRequestBody
6059
}
6160

6261
var req KickRequestSpec
6362
err = json.Unmarshal(body, &req)
6463
if err != nil {
65-
return nil, false, err.Error(), http.StatusBadRequest
64+
return nil, http.StatusBadRequest, err
6665
}
6766

6867
if apiSecret == "" || req.Secret != apiSecret {
69-
return nil, false, "Invalid API secret in request", http.StatusUnauthorized
68+
return nil, http.StatusUnauthorized, ErrInvalidSecret
7069
}
7170

7271
if req.ProfileID == 0 {
73-
return nil, false, "Profile ID missing or 0 in request", http.StatusBadRequest
72+
return nil, http.StatusBadRequest, ErrPIDMissing
7473
}
7574

7675
if req.Reason == "" {
77-
return nil, false, "Missing kick reason in request", http.StatusBadRequest
76+
return nil, http.StatusBadRequest, ErrReason
7877
}
7978

8079
gpcm.KickPlayerCustomMessage(req.ProfileID, req.Reason, gpcm.WWFCMsgKickedCustom)
8180

82-
var message string
8381
user, success := database.GetProfile(pool, ctx, req.ProfileID)
8482

85-
if success {
86-
message = ""
87-
} else {
88-
message = "Unable to query user data from the database"
83+
if !success {
84+
return nil, http.StatusInternalServerError, ErrUserQueryTransaction
8985
}
9086

91-
return &user, success, message, http.StatusOK
87+
return &user, http.StatusOK, nil
9288
}

0 commit comments

Comments
 (0)