Skip to content

Instantly share code, notes, and snippets.

@ppcamp
Created July 2, 2024 20:05
Show Gist options
  • Save ppcamp/10b12a89f90aa3daa7a5d053343dba6a to your computer and use it in GitHub Desktop.
Save ppcamp/10b12a89f90aa3daa7a5d053343dba6a to your computer and use it in GitHub Desktop.
Go simple server example with decorator JSON handler pattern
package main
import (
"context"
"encoding/json"
"errors"
"net"
"net/http"
"os"
"os/signal"
)
type Endpoints struct {
Descr string `json:"description_field,omitempty"`
}
func (s *Endpoints) test(r *http.Request) (JsonResp, error) {
return JsonResp{Status: 200, Body: Endpoints{Descr: r.PathValue("name")}}, nil
}
func main() {
basectx := context.Background()
ctx, stop := signal.NotifyContext(basectx, os.Interrupt)
defer stop()
// register
handlers := http.NewServeMux()
methods := &Endpoints{}
handlers.HandleFunc("GET /test/{name}", DecorateJSON(methods.test))
// setup server
server := &http.Server{Addr: ":8080", Handler: handlers, BaseContext: func(l net.Listener) context.Context {
return ctx
}}
go func() {
<-ctx.Done()
server.Shutdown(basectx)
}()
err := server.ListenAndServe()
if err != nil && !errors.Is(err, http.ErrServerClosed) {
panic(err)
}
}
type JsonResp struct {
Status int
Body any
}
type DecorateFunc func(r *http.Request) (JsonResp, error)
func DecorateJSON(fun DecorateFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
resp, err := fun(r)
if err != nil {
http.Error(w, "Internal server", http.StatusInternalServerError)
return
}
// RETURN JSON
w.Header().Set("Content-type", "text/json")
stringfied, err := json.MarshalIndent(resp.Body, "", " ")
if err != nil {
stringfied = []byte("Internal server error: failed to marshal JSON")
resp.Status = http.StatusInternalServerError
}
w.WriteHeader(resp.Status)
w.Write(stringfied)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment