Last active
July 20, 2016 01:07
-
-
Save squirly/53dcefcae05017ccb1c8419166518b6a to your computer and use it in GitHub Desktop.
post: golang context and di
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Database interface { } | |
type UserManager interface { | |
GetUser(id int) (User, error) | |
AuthenticateUser(username, password string) (int, error) | |
} | |
type User interface { | |
Id() int | |
Name() string | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func NewPooledDatabaseConnection(url string) Database { ... } | |
func NewDatabaseUserManager(databaseConn Database) UserManager { ... } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type userHttpHandler struct { | |
UserManager UserManager `inject:""` | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment