Skip to content

Instantly share code, notes, and snippets.

@hucancode
Last active April 18, 2025 06:33
Show Gist options
  • Save hucancode/40b968fb31a1f5c8767f1cd17e450193 to your computer and use it in GitHub Desktop.
Save hucancode/40b968fb31a1f5c8767f1cd17e450193 to your computer and use it in GitHub Desktop.
Lake Service API
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
}
}
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