Skip to content

Instantly share code, notes, and snippets.

@AarynSmith
Created May 2, 2018 17:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AarynSmith/03dae2ec1c729891a13d6647cfb34155 to your computer and use it in GitHub Desktop.
Save AarynSmith/03dae2ec1c729891a13d6647cfb34155 to your computer and use it in GitHub Desktop.
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)
}
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