Skip to content

Instantly share code, notes, and snippets.

@squirly
Last active July 20, 2016 01:07
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 squirly/53dcefcae05017ccb1c8419166518b6a to your computer and use it in GitHub Desktop.
Save squirly/53dcefcae05017ccb1c8419166518b6a to your computer and use it in GitHub Desktop.
post: golang context and di
func AddMessageMiddleware(message string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
oldCtx := nil // Get context from request
newCtx := oldCtx // modify context
next.ServeHTTP(w, r) // pass request to child handler
})
}
func AddMessageMiddleware(message string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
oldCtx := r.Context() // Get context from request
newCtx := oldCtx // modify context
next.ServeHTTP(w, r.WithContext(newCtx)) // pass request to child handler
})
}
func AddMessageMiddleware(message string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
oldCtx := r.Context() // Get context from request
newCtx := context.WithValue(oldCtx, "message", message) // modify context
next.ServeHTTP(w, r.WithContext(newCtx)) // pass request to child handler
})
}
const MessageContextKey = "message"
func AddMessageMiddleware(message string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), MessageContextKey, message)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func RespondWithMessage(w http.ResponseWriter, r *http.Request) {
message := r.Context().Value(MessageContextKey)
if message == nil {
http.Error(w, "No message provided", http.StatusInternalServerError)
} else {
w.WriteHeader(http.StatusOK)
w.Write([]byte(message.(string))) // possible panic from conversion
}
}
func main() {
helloHandler := AddMessageMiddleware("Hello!", http.HandlerFunc(RespondWithMessage))
goodbyeHandler := AddMessageMiddleware("Goodbye!", http.HandlerFunc(RespondWithMessage))
noMessageHandler := http.HandlerFunc(RespondWithMessage)
mux := new(http.ServeMux)
mux.Handle("/hello", helloHandler)
mux.Handle("/goodbye", goodbyeHandler)
mux.Handle("/error", noMessageHandler)
http.ListenAndServe(":8000", mux)
}
const MyDependencyContextKey = ""
type MyDependency interface {
Value() string
}
func MyHandler(w http.ResponseWriter, r *http.Request) {
myDependency := r.Context().Value(MyDependencyContextKey)
if myDependency == nil {
http.Error(w, "MyDependency does not exist", http.StatusInternalServerError)
return
} else {
dependency, ok := myDependency.(MyDependency)
if ok {
w.WriteHeader(http.StatusOK)
w.Write([]byte(dependency.Value()))
} else {
http.Error(w, ""MyDependency is of the wrong type."", http.StatusInternalServerError)
}
}
}
type Database interface { }
type UserManager interface {
GetUser(id int) (User, error)
AuthenticateUser(username, password string) (int, error)
}
type User interface {
Id() int
Name() string
}
func NewPooledDatabaseConnection(url string) Database { ... }
func NewDatabaseUserManager(databaseConn Database) UserManager { ... }
const UserIdContextKey = "UserId"
type Authenticator interface {
Authenticate(next http.Handler) http.Handler
}
type basicAuthenticator struct {
UserManager UserManager
}
func NewBasicAuthenticator(UserManager UserManager) Authenticator {
return basicAuthenticator{UserManager: UserManager}
}
func (a basicAuthenticator) Authenticate(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if ok {
userId, err := a.UserManager.AuthenticateUser(username, password)
if err == nil {
ctx := context.WithValue(r.Context(), UserIdContextKey, userId)
next.ServeHTTP(w, r.WithContext(ctx))
} else {
a.showLogin(w)
}
} else {
a.showLogin(w)
}
})
}
func (a basicAuthenticator) showLogin(w http.ResponseWriter) {
w.Header().Set("WWW-Authenticate", "Basic realm=\"Login\"")
http.Error(w, "Requires Login", http.StatusUnauthorized)
}
type userHttpHandler struct {
userManager UserManager
}
func NewUserHttpHandler(userManager UserManager) http.Handler {
return userHttpHandler{userManager: userManager}
}
func (h userHttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
userId := r.Context().Value(UserIdContextKey)
if userId == nil {
http.Error(w, "No user", http.StatusInternalServerError)
} else {
user, err := h.userManager.GetUser(userId.(int))
if err == nil {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Hello %s!", user.Name())
} else {
http.Error(w, "No user", http.StatusNotFound)
}
}
} else {
http.Error(w, "Invalid Method", http.StatusMethodNotAllowed)
}
}
func main() {
// create dependencies
databaseConn := NewPooledDatabaseConnection("user:pass@localhost:3000")
userManager := NewDatabaseUserManager(databaseConn)
// setup handler
authenticator := NewBasicAuthenticator(userManager)
userHttpHandler := NewUserHttpHandler(userManager)
// create and run the server
mux := http.NewServeMux()
mux.Handle("/user", userHttpHandler)
server := &http.Server{
Addr: ":8080",
Handler: authenticator.Authenticate(mux),
}
err := server.ListenAndServe()
if err != nil {
fmt.Println(err.Error())
}
}
type userHttpHandler struct {
UserManager UserManager `inject:""`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment