Created
May 2, 2018 17:33
-
-
Save AarynSmith/03dae2ec1c729891a13d6647cfb34155 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"fmt" | |
"log" | |
"net/http" | |
"strconv" | |
"github.com/gorilla/mux" | |
) | |
type app struct { | |
Router *mux.Router | |
UserDB map[int]user | |
} | |
type user struct { | |
ID int | |
Name string | |
Role string | |
} | |
func main() { | |
a := app{} | |
a.Router = mux.NewRouter() | |
a.UserDB = map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
} | |
a.AddHandles() | |
a.Run(":3001") | |
} | |
func (a *app) AddHandles() { | |
a.Router.HandleFunc("/user/{id:[0-9]+}", a.GetUser).Methods("GET") | |
a.Router.HandleFunc("/user", a.CreateUser).Methods("POST") | |
a.Router.HandleFunc("/user/{id:[0-9]+}", a.DeleteUser).Methods("DELETE") | |
a.Router.HandleFunc("/user/{id:[0-9]+}", a.ReplaceUser).Methods("PUT") | |
a.Router.HandleFunc("/user/{id:[0-9]+}", a.UpdateUser).Methods("PATCH") | |
} | |
func (a *app) Run(addr string) (err error) { | |
log.Printf("Listening on %v", addr) | |
return http.ListenAndServe(addr, a.Router) | |
} | |
func (a *app) GetUser(w http.ResponseWriter, req *http.Request) { | |
vars := mux.Vars(req) | |
id, err := strconv.Atoi(vars["id"]) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "500 Internal Server Error\n") | |
return | |
} | |
_, ok := a.UserDB[id] | |
if !ok { | |
w.WriteHeader(404) | |
fmt.Fprintf(w, "404 page not found\n") | |
return | |
} | |
j, err := json.Marshal(a.UserDB[id]) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "500 Internal Server Error\n") | |
return | |
} | |
fmt.Fprint(w, string(j)) | |
} | |
func maxID(d map[int]user) (m int) { | |
for k := range d { | |
if k > m { | |
m = k | |
} | |
} | |
return m | |
} | |
func (a *app) CreateUser(w http.ResponseWriter, req *http.Request) { | |
nextID := maxID(a.UserDB) + 1 | |
p := user{} | |
buf := new(bytes.Buffer) | |
buf.ReadFrom(req.Body) | |
err := json.Unmarshal(buf.Bytes(), &p) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "500 Internal Server Error\n") | |
return | |
} | |
a.UserDB[nextID] = p | |
w.Header().Set("Location", | |
fmt.Sprintf("http://%s/user/%d", req.Host, nextID)) | |
w.WriteHeader(200) | |
} | |
func (a *app) DeleteUser(w http.ResponseWriter, req *http.Request) { | |
vars := mux.Vars(req) | |
id, err := strconv.Atoi(vars["id"]) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "Could not delete user: %v", err.Error()) | |
return | |
} | |
_, ok := a.UserDB[id] | |
if !ok { | |
w.WriteHeader(404) | |
fmt.Fprintf(w, "404 page not found\n") | |
return | |
} | |
delete(a.UserDB, id) | |
w.WriteHeader(200) | |
} | |
func (a *app) ReplaceUser(w http.ResponseWriter, req *http.Request) { | |
vars := mux.Vars(req) | |
id, err := strconv.Atoi(vars["id"]) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "Could not delete user: %v", err.Error()) | |
return | |
} | |
p := user{} | |
buf := new(bytes.Buffer) | |
buf.ReadFrom(req.Body) | |
err = json.Unmarshal(buf.Bytes(), &p) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "500 Internal Server Error\n") | |
return | |
} | |
_, ok := a.UserDB[id] | |
if !ok { | |
w.WriteHeader(404) | |
fmt.Fprintf(w, "404 page not found\n") | |
return | |
} | |
p.ID = id | |
a.UserDB[id] = p | |
w.WriteHeader(200) | |
} | |
func (a *app) UpdateUser(w http.ResponseWriter, req *http.Request) { | |
vars := mux.Vars(req) | |
id, err := strconv.Atoi(vars["id"]) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "Could not delete user: %v", err.Error()) | |
return | |
} | |
pNew := user{} | |
buf := new(bytes.Buffer) | |
buf.ReadFrom(req.Body) | |
err = json.Unmarshal(buf.Bytes(), &pNew) | |
if err != nil { | |
w.WriteHeader(500) | |
fmt.Fprintf(w, "500 Internal Server Error\n") | |
return | |
} | |
_, ok := a.UserDB[id] | |
if !ok { | |
w.WriteHeader(404) | |
fmt.Fprintf(w, "404 page not found\n") | |
return | |
} | |
pNew.ID = id | |
if pNew.Name == "" { | |
pNew.Name = a.UserDB[id].Name | |
} | |
if pNew.Role == "" { | |
pNew.Role = a.UserDB[id].Role | |
} | |
a.UserDB[id] = pNew | |
w.WriteHeader(200) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"net/http" | |
"net/http/httptest" | |
"strings" | |
"testing" | |
"github.com/gorilla/mux" | |
) | |
func executeRequest(req *http.Request, db map[int]user) *httptest.ResponseRecorder { | |
rr := httptest.NewRecorder() | |
a := app{} | |
a.Router = mux.NewRouter() | |
a.UserDB = db | |
a.AddHandles() | |
a.Router.ServeHTTP(rr, req) | |
return rr | |
} | |
func Test_app_GetUser(t *testing.T) { | |
tests := []struct { | |
database map[int]user | |
method string | |
request string | |
expectedCode int | |
}{ | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "GET", | |
request: "/user/1", | |
expectedCode: 200, | |
}, | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "GET", | |
request: "/user/2", | |
expectedCode: 404, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "GET", | |
request: "/user/1", | |
expectedCode: 404, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "GET", | |
request: "/user/99999999999999999999", | |
expectedCode: 500, | |
}, | |
} | |
for _, tt := range tests { | |
req, _ := http.NewRequest(tt.method, tt.request, nil) | |
response := executeRequest(req, tt.database) | |
if tt.expectedCode != response.Code { | |
t.Errorf("Expected response code %d. Got %d.\n", tt.expectedCode, response.Code) | |
} | |
} | |
} | |
func Test_app_DeleteUser(t *testing.T) { | |
tests := []struct { | |
database map[int]user | |
method string | |
request string | |
expectedCode int | |
}{ | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "DELETE", | |
request: "/user/1", | |
expectedCode: 200, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "DELETE", | |
request: "/user/1", | |
expectedCode: 404, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "DELETE", | |
request: "/user/99999999999999999999", | |
expectedCode: 500, | |
}, | |
} | |
for _, tt := range tests { | |
req, _ := http.NewRequest(tt.method, tt.request, nil) | |
response := executeRequest(req, tt.database) | |
if tt.expectedCode != response.Code { | |
t.Errorf("Expected response code %d. Got %d.\n", tt.expectedCode, response.Code) | |
} | |
} | |
} | |
func Test_app_CreateUser(t *testing.T) { | |
tests := []struct { | |
database map[int]user | |
method string | |
request string | |
body string | |
expectedCode int | |
}{ | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "POST", | |
request: "/user", | |
body: `{"name": "User 2","role":"User"}`, | |
expectedCode: 200, | |
}, | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "POST", | |
request: "/user", | |
body: `Not a JSON string`, | |
expectedCode: 500, | |
}, | |
} | |
for _, tt := range tests { | |
body := strings.NewReader(tt.body) | |
req, _ := http.NewRequest(tt.method, tt.request, body) | |
response := executeRequest(req, tt.database) | |
if tt.expectedCode != response.Code { | |
t.Errorf("Expected response code %d. Got %d.\n", tt.expectedCode, response.Code) | |
} | |
} | |
} | |
func Test_app_ReplaceUser(t *testing.T) { | |
tests := []struct { | |
database map[int]user | |
method string | |
request string | |
body string | |
expectedCode int | |
}{ | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "PUT", | |
request: "/user/1", | |
body: `{"name": "User 2","role":"User"}`, | |
expectedCode: 200, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "PUT", | |
request: "/user/1", | |
body: `Not a JSON string`, | |
expectedCode: 500, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "PUT", | |
request: "/user/1", | |
body: `{"name": "User 2","role":"User"}`, | |
expectedCode: 404, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "PUT", | |
request: "/user/99999999999999999999", | |
body: `{"name": "User 2","role":"User"}`, | |
expectedCode: 500, | |
}, | |
} | |
for _, tt := range tests { | |
body := strings.NewReader(tt.body) | |
req, _ := http.NewRequest(tt.method, tt.request, body) | |
response := executeRequest(req, tt.database) | |
if tt.expectedCode != response.Code { | |
t.Errorf("Expected response code %d. Got %d.\n", tt.expectedCode, response.Code) | |
} | |
} | |
} | |
func Test_app_UpdateUser(t *testing.T) { | |
tests := []struct { | |
database map[int]user | |
method string | |
request string | |
body string | |
expectedCode int | |
}{ | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "PATCH", | |
request: "/user/1", | |
body: `{"name": "User 2"}`, | |
expectedCode: 200, | |
}, | |
{ | |
database: map[int]user{ | |
1: user{ | |
ID: 1, | |
Name: "User 1", | |
Role: "Admin", | |
}, | |
}, | |
method: "PATCH", | |
request: "/user/1", | |
body: `{"role": "User"}`, | |
expectedCode: 200, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "PATCH", | |
request: "/user/1", | |
body: `Not a JSON string`, | |
expectedCode: 500, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "PATCH", | |
request: "/user/1", | |
body: `{"name": "User 2","role":"User"}`, | |
expectedCode: 404, | |
}, | |
{ | |
database: map[int]user{}, | |
method: "PATCH", | |
request: "/user/99999999999999999999", | |
body: `{"name": "User 2","role":"User"}`, | |
expectedCode: 500, | |
}, | |
} | |
for _, tt := range tests { | |
body := strings.NewReader(tt.body) | |
req, _ := http.NewRequest(tt.method, tt.request, body) | |
response := executeRequest(req, tt.database) | |
if tt.expectedCode != response.Code { | |
t.Errorf("Expected response code %d. Got %d.\n", tt.expectedCode, response.Code) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment