Skip to content

Instantly share code, notes, and snippets.

@vadviktor
Last active June 18, 2025 11:05
Show Gist options
  • Save vadviktor/6273e4afd1753b6bf48974e55aee9836 to your computer and use it in GitHub Desktop.
Save vadviktor/6273e4afd1753b6bf48974e55aee9836 to your computer and use it in GitHub Desktop.
Go stdlib http server with api and embedded SPA (e.g. React)
package main
import (
"embed"
"encoding/json"
"fmt"
"io"
"io/fs"
"log"
"net/http"
)
//go:embed static
var staticFiles embed.FS
type CreateRequest struct {
Name string `json:"name"`
}
type APIResponse struct {
Message string `json:"message"`
}
type CreateResponse struct {
Created string `json:"created"`
}
func main() {
mux := http.NewServeMux()
// Serve static files from embedded FS at root
// Since we embedded "static", we need to serve from the "static" subdirectory
staticFS, err := http.FS(staticFiles).Open("static")
if err != nil {
log.Fatal("Failed to open static directory:", err)
}
staticFS.Close()
// Create a sub filesystem that serves from the static directory
subFS, err := fs.Sub(staticFiles, "static")
if err != nil {
log.Fatal("Failed to create sub filesystem:", err)
}
staticHandler := http.FileServer(http.FS(subFS))
mux.Handle("/", staticHandler)
// API endpoint that returns JSON
mux.HandleFunc("GET /api", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
response := APIResponse{Message: "hello from api"}
json.NewEncoder(w).Encode(response)
})
// POST endpoint for creating
mux.HandleFunc("POST /api/create", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
return
}
defer r.Body.Close()
var req CreateRequest
if err := json.Unmarshal(body, &req); err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// Log the received name for debugging
log.Printf("Received create request for: %s", req.Name)
response := CreateResponse{Created: "ok"}
json.NewEncoder(w).Encode(response)
})
fmt.Println("Server starting on port 16000...")
fmt.Println("Static files served from: /")
fmt.Println("API endpoint: GET /api")
fmt.Println("Create endpoint: POST /api/create")
log.Fatal(http.ListenAndServe(":16000", mux))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment