commit a50e4162b37b4d679e3ecfdd5b6e8697161c13dd Author: Steve Date: Thu Mar 3 13:28:00 2022 -0500 inital skeleton diff --git a/README.md b/README.md new file mode 100644 index 0000000..aaac139 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# freego_api +freego implementation as a simple REST API. + +Currently stores no state and has no user authentication, so using it should just be + go build + ./freego_api diff --git a/api.go b/api.go new file mode 100644 index 0000000..7a55036 --- /dev/null +++ b/api.go @@ -0,0 +1,85 @@ +package main + +import ( + "encoding/json" + "net/http" + "strconv" + + "github.com/gorilla/mux" +) + +//API represents the api +type API struct { + games map[int]*Session + nextInt int +} + +//NewAPI creates new API instance +func NewAPI() *API { + return &API{ + games: make(map[int]*Session), + nextInt: 1, + } +} + +//NewGame takes a POST and creates a new game +func (a *API) NewGame(res http.ResponseWriter, req *http.Request) { + a.games[a.nextInt] = NewSession() + respondWithJSON(res, http.StatusOK, newGameResp{a.nextInt, "red"}) + a.nextInt = a.nextInt + 1 +} + +//GetGame returns current state of game, filtered accordingly +func (a *API) GetGame(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid game ID") + return + } + var gr gameReq + decoder := json.NewDecoder(req.Body) + if err := decoder.Decode(&gr); err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid resquest payload") + return + } + defer req.Body.Close() + if gr.PlayerID != "red" && gr.PlayerID != "blue" { + respondWithError(res, http.StatusBadRequest, "Bad player ID") + return + } + s, isset := a.games[id] + if !isset { + respondWithError(res, http.StatusBadRequest, "No such game") + return + } + respondWithJSON(res, http.StatusOK, gameResp{s.simulator}) + return +} + +//GetGameStatus returns current game status and turn number +func (a *API) GetGameStatus(res http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + id, err := strconv.Atoi(vars["id"]) + if err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid game ID") + return + } + var gr gameReq + decoder := json.NewDecoder(req.Body) + if err := decoder.Decode(&gr); err != nil { + respondWithError(res, http.StatusBadRequest, "Invalid resquest payload") + return + } + defer req.Body.Close() + if gr.PlayerID != "red" && gr.PlayerID != "blue" { + respondWithError(res, http.StatusBadRequest, "Bad player ID") + return + } + s, isset := a.games[id] + if !isset { + respondWithError(res, http.StatusBadRequest, "No such game") + return + } + respondWithJSON(res, http.StatusOK, gameStatusResp{s.simulator.State, s.moveNum}) +} diff --git a/api_types.go b/api_types.go new file mode 100644 index 0000000..5def71c --- /dev/null +++ b/api_types.go @@ -0,0 +1,27 @@ +package main + +import "git.saintnet.tech/freego" + +//type newGameReq struct{} + +type newGameResp struct { + GameID int `json:"game_id"` + PlayerID string `json:"player_id"` +} + +type gameReq struct { + PlayerID string `json:"player_id"` +} + +type gameResp struct { + GameBoard *freego.Game `json:"board"` +} + +type gameStatusReq struct { + PlayerID string `json:"player_id"` +} + +type gameStatusResp struct { + GameStatus freego.GameState `json:"game_status"` + Move int `json:"move"` +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7a4fdfe --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module git.saintnet.tech/freego_api + +replace git.saintnet.tech/freego => ../freego + +go 1.17 + +require ( + git.saintnet.tech/freego v0.0.0-00010101000000-000000000000 // indirect + github.com/gorilla/mux v1.8.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5350288 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= diff --git a/main.go b/main.go new file mode 100644 index 0000000..eff0b12 --- /dev/null +++ b/main.go @@ -0,0 +1,21 @@ +package main + +import ( + "log" + "net/http" + + "github.com/gorilla/mux" +) + +func main() { + api := NewAPI() + router := mux.NewRouter().StrictSlash(true) + //plot out routes + router.HandleFunc("/game", api.NewGame).Methods("POST") + router.HandleFunc("/game/{id}", api.GetGame).Methods("GET") + router.HandleFunc("/game/{id}/status", api.GetGameStatus).Methods("GET") + router.HandleFunc("/game/{id}/move", nil).Methods("POST") + router.HandleFunc("/game/{id}/move/{movenum}", nil).Methods("GET") + log.Fatal(http.ListenAndServe(":1379", router)) + +} diff --git a/session.go b/session.go new file mode 100644 index 0000000..e156e71 --- /dev/null +++ b/session.go @@ -0,0 +1,21 @@ +package main + +import "git.saintnet.tech/freego" + +//Session represents an active game +type Session struct { + simulator *freego.Game + redReady bool + blueReady bool + moveNum int +} + +//NewSession creates a new game session +func NewSession() *Session { + return &Session{ + simulator: freego.NewGame(), + redReady: false, + blueReady: false, + moveNum: 0, + } +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..1528156 --- /dev/null +++ b/util.go @@ -0,0 +1,18 @@ +package main + +import ( + "encoding/json" + "net/http" +) + +func respondWithError(res http.ResponseWriter, code int, message string) { + respondWithJSON(res, code, map[string]string{"error": message}) +} + +func respondWithJSON(res http.ResponseWriter, code int, payload interface{}) { + response, _ := json.Marshal(payload) + + res.Header().Set("Content-Type", "application/json") + res.WriteHeader(code) + res.Write(response) +}