Last active
April 18, 2025 06:33
-
-
Save hucancode/40b968fb31a1f5c8767f1cd17e450193 to your computer and use it in GitHub Desktop.
Lake Service API
This file contains 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 ( | |
"encoding/json" | |
"fmt" | |
"net/http" | |
"strconv" | |
) | |
const CONCURRENT_EVENTS = 1000 | |
type Lake struct { | |
Name string `json:"name"` | |
Area float64 `json:"area"` | |
Depth float64 `json:"depth"` | |
Location string `json:"location"` | |
} | |
type LakeService struct { | |
data map[int]Lake | |
counter int | |
} | |
func NewLakeService() *LakeService { | |
return &LakeService{ | |
data: make(map[int]Lake), | |
counter: 0, | |
} | |
} | |
func (self *LakeService) getLake(w http.ResponseWriter, r *http.Request) { | |
idStr := r.PathValue("id") | |
id, err := strconv.Atoi(idStr) | |
if err != nil { | |
http.Error(w, "Invalid ID", http.StatusBadRequest) | |
return | |
} | |
lake, exists := self.data[id] | |
if !exists { | |
http.Error(w, "Lake not found", http.StatusNotFound) | |
return | |
} | |
w.Header().Set("Content-Type", "application/json") | |
json.NewEncoder(w).Encode(lake) | |
} | |
func (self *LakeService) createLake(w http.ResponseWriter, r *http.Request) { | |
var newLake Lake | |
err := json.NewDecoder(r.Body).Decode(&newLake) | |
if err != nil { | |
http.Error(w, fmt.Sprintf("Invalid input %v", err), http.StatusBadRequest) | |
return | |
} | |
ret := self.counter | |
self.data[self.counter] = newLake | |
self.counter++ | |
w.Header().Set("Content-Type", "application/json") | |
json.NewEncoder(w).Encode(ret) | |
} | |
func (self *LakeService) deleteLake(w http.ResponseWriter, r *http.Request) { | |
idStr := r.PathValue("id") | |
id, err := strconv.Atoi(idStr) | |
if err != nil { | |
http.Error(w, "Invalid ID", http.StatusBadRequest) | |
return | |
} | |
_, exists := self.data[id] | |
if exists { | |
delete(self.data, id) | |
} | |
if !exists { | |
http.Error(w, "Lake not found", http.StatusNotFound) | |
return | |
} | |
w.WriteHeader(http.StatusNoContent) | |
} | |
func (self *LakeService) updateLake(w http.ResponseWriter, r *http.Request) { | |
idStr := r.PathValue("id") | |
id, err := strconv.Atoi(idStr) | |
if err != nil { | |
http.Error(w, "Invalid ID", http.StatusBadRequest) | |
return | |
} | |
var updatedLake Lake | |
_, exists := self.data[id] | |
if !exists { | |
http.Error(w, "Lake not found", http.StatusNotFound) | |
return | |
} | |
err = json.NewDecoder(r.Body).Decode(&updatedLake) | |
if err != nil { | |
http.Error(w, "Invalid input", http.StatusBadRequest) | |
return | |
} | |
self.data[id] = updatedLake | |
w.Header().Set("Content-Type", "application/json") | |
json.NewEncoder(w).Encode(updatedLake) | |
} | |
func (self *LakeService) getLakes(w http.ResponseWriter, r *http.Request) { | |
w.Header().Set("Content-Type", "application/json") | |
json.NewEncoder(w).Encode(self.data) | |
} | |
func makeRouter(service *LakeService) http.Handler { | |
mux := http.NewServeMux() | |
mux.HandleFunc("GET /lakes", service.getLakes) | |
mux.HandleFunc("POST /lakes", service.createLake) | |
mux.HandleFunc("GET /lake/{id}", service.getLake) | |
mux.HandleFunc("DELETE /lake/{id}", service.deleteLake) | |
mux.HandleFunc("PATCH /lake/{id}", service.updateLake) | |
return mux | |
} | |
func main() { | |
service := NewLakeService() | |
router := makeRouter(service) | |
fmt.Println("Listening on port 8080...") | |
err := http.ListenAndServe(":8080", router) | |
if err != nil { | |
fmt.Println("Error starting server:", err) | |
return | |
} | |
} |
This file contains 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" | |
) | |
func TestCreateLake(t *testing.T) { | |
service := NewLakeService() | |
router := makeRouter(service) | |
req, err := http.NewRequest("POST", "/lakes", strings.NewReader(`{"name": "Lake A", "area": 100.0, "depth": 50.0, "location": "Location A"}`)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
req.Header.Set("Content-Type", "application/json") | |
rr := httptest.NewRecorder() | |
router.ServeHTTP(rr, req) | |
if status := rr.Code; status != http.StatusOK { | |
t.Errorf("handler returned wrong status code: got %v want %v", | |
status, http.StatusOK) | |
} | |
expectedBody := "0" | |
if body := strings.TrimSpace(rr.Body.String()); body != expectedBody { | |
t.Errorf("handler returned unexpected body: got %v want %v", | |
body, expectedBody) | |
} | |
} | |
func TestGetLake(t *testing.T) { | |
service := NewLakeService() | |
router := makeRouter(service) | |
// First create a lake | |
createReq, err := http.NewRequest("POST", "/lakes", strings.NewReader(`{"name": "Lake A", "area": 100.0, "depth": 50.0, "location": "Location A"}`)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
createReq.Header.Set("Content-Type", "application/json") | |
router.ServeHTTP(httptest.NewRecorder(), createReq) | |
// Then get the lake | |
req, err := http.NewRequest("GET", "/lake/0", nil) | |
if err != nil { | |
t.Fatal(err) | |
} | |
rr := httptest.NewRecorder() | |
router.ServeHTTP(rr, req) | |
if status := rr.Code; status != http.StatusOK { | |
t.Errorf("handler returned wrong status code: got %v want %v", | |
status, http.StatusOK) | |
} | |
expectedBody := `{"name":"Lake A","area":100,"depth":50,"location":"Location A"}` | |
if body := strings.TrimSpace(rr.Body.String()); body != expectedBody { | |
t.Errorf("handler returned unexpected body: got %v want %v", | |
body, expectedBody) | |
} | |
} | |
func TestUpdateLake(t *testing.T) { | |
service := NewLakeService() | |
router := makeRouter(service) | |
// First create a lake | |
createReq, err := http.NewRequest("POST", "/lakes", strings.NewReader(`{"name": "Lake A", "area": 100.0, "depth": 50.0, "location": "Location A"}`)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
createReq.Header.Set("Content-Type", "application/json") | |
router.ServeHTTP(httptest.NewRecorder(), createReq) | |
// Then update the lake | |
req, err := http.NewRequest("PATCH", "/lake/0", strings.NewReader(`{"name": "Lake A Updated", "area": 150.0, "depth": 60.0, "location": "Location A Updated"}`)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
req.Header.Set("Content-Type", "application/json") | |
rr := httptest.NewRecorder() | |
router.ServeHTTP(rr, req) | |
if status := rr.Code; status != http.StatusOK { | |
t.Errorf("handler returned wrong status code: got %v want %v", | |
status, http.StatusOK) | |
} | |
expectedBody := `{"name":"Lake A Updated","area":150,"depth":60,"location":"Location A Updated"}` | |
if body := strings.TrimSpace(rr.Body.String()); body != expectedBody { | |
t.Errorf("handler returned unexpected body: got %v want %v", | |
body, expectedBody) | |
} | |
} | |
func TestDeleteLake(t *testing.T) { | |
service := NewLakeService() | |
router := makeRouter(service) | |
// First create a lake | |
createReq, err := http.NewRequest("POST", "/lakes", strings.NewReader(`{"name": "Lake A", "area": 100.0, "depth": 50.0, "location": "Location A"}`)) | |
if err != nil { | |
t.Fatal(err) | |
} | |
createReq.Header.Set("Content-Type", "application/json") | |
router.ServeHTTP(httptest.NewRecorder(), createReq) | |
// Then delete the lake | |
req, err := http.NewRequest("DELETE", "/lake/0", nil) | |
if err != nil { | |
t.Fatal(err) | |
} | |
rr := httptest.NewRecorder() | |
router.ServeHTTP(rr, req) | |
if status := rr.Code; status != http.StatusNoContent { | |
t.Errorf("handler returned wrong status code: got %v want %v", | |
status, http.StatusNoContent) | |
} | |
// Verify lake is deleted by trying to get it | |
getReq, err := http.NewRequest("GET", "/lake/0", nil) | |
if err != nil { | |
t.Fatal(err) | |
} | |
getRr := httptest.NewRecorder() | |
router.ServeHTTP(getRr, getReq) | |
if status := getRr.Code; status != http.StatusNotFound { | |
t.Errorf("handler returned wrong status code: got %v want %v", | |
status, http.StatusNotFound) | |
} | |
expectedBody := "Lake not found" | |
if body := strings.TrimSpace(getRr.Body.String()); body != expectedBody { | |
t.Errorf("handler returned unexpected body: got %v want %v", | |
body, expectedBody) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment