Skip to content

Instantly share code, notes, and snippets.

@DeedleFake
Last active September 7, 2023 19:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DeedleFake/05eb4adad4f23a295a8038a2101c0445 to your computer and use it in GitHub Desktop.
Save DeedleFake/05eb4adad4f23a295a8038a2101c0445 to your computer and use it in GitHub Desktop.
An example of a very, very basic structure for a simple REST API in Go.
package main
import (
"context"
"database/sql"
"fmt"
"log/slog"
"net"
"net/http"
"os"
"os/signal"
)
type Server struct {
Addr string
db *sql.DB
}
func (s *Server) Run(ctx context.Context) error {
err := s.openDB(ctx)
if err != nil {
return fmt.Errorf("open database: %w", err)
}
defer s.db.Close()
server := http.Server{
Addr: ":8080",
Handler: s.createRouter(),
BaseContext: func(net.Listener) context.Context { return ctx },
}
// TODO: Setup graceful shutdown handling and whatnot.
err = server.ListenAndServe()
if err != nil {
return fmt.Errorf("listen and server: %w", err)
}
return nil
}
func (s *Server) openDB(ctx context.Context) error {
panic("Not implemented.")
}
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
server := Server{
Addr: ":8080", // TODO: Get this from somewhere.
}
err := server.Run(ctx)
if err != nil {
slog.Error("fatal error", "err", err)
os.Exit(1)
}
}
module http-structure-example
go 1.21.0
require github.com/julienschmidt/httprouter v1.3.0
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
package main
import (
"log/slog"
"net/http"
)
// This could all probably be put into a package just for middleware or something.
func Log(h http.Handler, logger *slog.Logger) http.Handler {
if logger == nil {
logger = slog.Default()
}
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
logger.Info("handle request", "method", req.Method, "url", req.URL.RequestURI())
h.ServeHTTP(rw, req)
})
}
package main
import (
"net/http"
"github.com/julienschmidt/httprouter"
)
func (s *Server) createRouter() http.Handler {
router := httprouter.New()
router.Handler(http.MethodGet, "/user", Log(GetUser{DB: s.db}, nil))
router.Handler(http.MethodPost, "/user", Log(CreateUser{DB: s.db}, nil))
return router
}
package main
import (
"database/sql"
"net/http"
)
// These can be moved into other packages in the module and whatnot if
// necessary as the number of endpoints increases.
type GetUser struct {
DB *sql.DB
}
func (h GetUser) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
panic("Not implemented.")
}
type CreateUser struct {
DB *sql.DB
}
func (h CreateUser) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
panic("Not implemented.")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment