| package main | |
| import ( | |
| "net/http" | |
| "database/sql" | |
| "fmt" | |
| "log" | |
| "os" | |
| ) | |
| func helloHandler(db *sql.DB) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| var name string | |
| // Execute the query. | |
| row := db.QueryRow("SELECT myname FROM mytable") | |
| if err := row.Scan(&name); err != nil { | |
| http.Error(w, err.Error(), 500) | |
| return | |
| } | |
| // Write it back to the client. | |
| fmt.Fprintf(w, "hi %s!\n", name) | |
| }) | |
| } | |
| func withMetrics(l *log.Logger, next http.Handler) http.Handler { | |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| began := time.Now() | |
| next.ServeHTTP(w, r) | |
| l.Printf("%s %s took %s", r.Method, r.URL, time.Since(began)) | |
| }) | |
| } | |
| func main() { | |
| // Open our database connection. | |
| db, err := sql.Open("postgres", "…") | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| // Create our logger | |
| logger := log.New(os.Stdout, "", 0) | |
| // Register our handler. | |
| http.Handle("/hello", helloHandler(db)) | |
| // Register our handler with metrics logging | |
| http.Handle("/hello_again", withMetrics(logger, helloHandler(db))) | |
| http.ListenAndServe(":8080", nil) | |
| } |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
alexedwards
commented
Oct 4, 2014
|
I really like this approach. Just wondering - Is there any advantage/disadvantage of doing it the above way instead of creating a custom DB type and defining handlers as methods against it? Like so... type MyDB struct {
*sql.DB
}
func(db *MyDB) handlerOne(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do something databasey
})
}
func(db *MyDB) handlerTwo() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Do something else databasey
})
}
func main() {
db, err := sql.Open("postgres", "…")
// Handle
mydb := &MyDB{db}
http.Handle("/", myDB.handlerOne(myDB.handlerTwo()))
// Etc.
}It seems to me that the nice thing with this is that the middleware handler (handlerOne) retains the form |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
crossle
commented
Aug 31, 2017
|
Why not store db connect to context? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Jeiwan
Dec 25, 2017
@crossle DB connections are usually opened once, when the app starts, and reused later. Contexts are for things that are started/initialized/created per request or per operation.
Jeiwan
commented
Dec 25, 2017
•
|
@crossle DB connections are usually opened once, when the app starts, and reused later. Contexts are for things that are started/initialized/created per request or per operation. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
gerep
Jan 4, 2018
@crossle Use context Values only for request-scoped data that transits processes and APIs, not for passing optional parameters to functions. - https://godoc.org/golang.org/x/net/context
gerep
commented
Jan 4, 2018
•
|
@crossle |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mikeschinkel
Apr 14, 2018
This was super helpful to me as I have been learning GoLang. Thanks for posting!
mikeschinkel
commented
Apr 14, 2018
|
This was super helpful to me as I have been learning GoLang. Thanks for posting! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ldelossa
commented
Apr 26, 2018
|
+1 this is good. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
smurariu
May 8, 2018
@alexedwards I don't think there's an advantage or disadvantage but it does somewhat limit the explosion of types/interfaces. And I'm guessing that in some scenarios you'll want to use your approach in others this one so it's really useful to be aware of both.
smurariu
commented
May 8, 2018
|
@alexedwards I don't think there's an advantage or disadvantage but it does somewhat limit the explosion of types/interfaces. And I'm guessing that in some scenarios you'll want to use your approach in others this one so it's really useful to be aware of both. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
montera82
May 23, 2018
and how do you write a test against the handler hellohandler using this approach?
montera82
commented
May 23, 2018
|
and how do you write a test against the handler |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
adam-erickson
May 23, 2018
The main issue with the @tsenart method is if both your handlers and handles live in a separate package from your main database instance. This still requires creating a struct or global variable in order to pass the database to these functions from main. Hence, I don't consider it a very realistic solution for large projects. In terms of package layout and compartmentalization, the method used here looks very nice: https://hackernoon.com/make-yourself-a-go-web-server-with-mongodb-go-on-go-on-go-on-48f394f24e
adam-erickson
commented
May 23, 2018
|
The main issue with the @tsenart method is if both your handlers and handles live in a separate package from your main database instance. This still requires creating a struct or global variable in order to pass the database to these functions from main. Hence, I don't consider it a very realistic solution for large projects. In terms of package layout and compartmentalization, the method used here looks very nice: https://hackernoon.com/make-yourself-a-go-web-server-with-mongodb-go-on-go-on-go-on-48f394f24e |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Carlislegroup
Jun 20, 2018
Diving into best practices to separate DB from code for scalability/flexibility, and came here from ben johnson's post (https://medium.com/@benbjohnson/structuring-applications-in-go-3b04be4ff091). Thank you for putting this together. Is there any blog posts on how to write tests against this approach? Thanks!
Carlislegroup
commented
Jun 20, 2018
|
Diving into best practices to separate DB from code for scalability/flexibility, and came here from ben johnson's post (https://medium.com/@benbjohnson/structuring-applications-in-go-3b04be4ff091). Thank you for putting this together. Is there any blog posts on how to write tests against this approach? Thanks! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ace3
commented
Jul 1, 2018
|
+1 very helpful |
I really like this approach.
Just wondering - Is there any advantage/disadvantage of doing it the above way instead of creating a custom DB type and defining handlers as methods against it? Like so...
It seems to me that the nice thing with this is that the middleware handler (handlerOne) retains the form
func (http.Handler) http.Handlermeaning it can be used nicely for chaining in the Alice style.