feat: middleware, expvar
This commit is contained in:
@@ -3,8 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"expvar"
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -34,7 +36,8 @@ type config struct {
|
|||||||
maxOpenConns int
|
maxOpenConns int
|
||||||
maxIdleConns int
|
maxIdleConns int
|
||||||
maxIdleTime string
|
maxIdleTime string
|
||||||
} // Add a new limiter struct containing fields for the requests-per-second and burst
|
}
|
||||||
|
// Add a new limiter struct containing fields for the requests-per-second and burst
|
||||||
// values, and a boolean field which we can use to enable/disable rate limiting
|
// values, and a boolean field which we can use to enable/disable rate limiting
|
||||||
// altogether.
|
// altogether.
|
||||||
limiter struct {
|
limiter struct {
|
||||||
@@ -138,6 +141,23 @@ func main() {
|
|||||||
// established.
|
// established.
|
||||||
logger.PrintInfo("database connection pool established", nil)
|
logger.PrintInfo("database connection pool established", nil)
|
||||||
|
|
||||||
|
// Publish a new "version" variable in the expvar handler containing our application
|
||||||
|
// version number (currently the constant "1.0.0").
|
||||||
|
expvar.NewString("version").Set(version)
|
||||||
|
expvar.Publish("goroutines", expvar.Func(func() any {
|
||||||
|
return runtime.NumGoroutine()
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Publish the database connection pool statistics.
|
||||||
|
expvar.Publish("database", expvar.Func(func() any {
|
||||||
|
return db.Stats()
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Publish the current Unix timestamp.
|
||||||
|
expvar.Publish("timestamp", expvar.Func(func() any {
|
||||||
|
return time.Now().Unix()
|
||||||
|
}))
|
||||||
|
|
||||||
app := &application{
|
app := &application{
|
||||||
config: cfg,
|
config: cfg,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
|||||||
@@ -247,27 +247,36 @@ func (app *application) requirePermission(code string, next http.HandlerFunc) ht
|
|||||||
|
|
||||||
func (app *application) enableCORS(next http.Handler) http.Handler {
|
func (app *application) enableCORS(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// Add the "Vary: Origin" header.
|
|
||||||
w.Header().Add("Vary", "Origin")
|
w.Header().Add("Vary", "Origin")
|
||||||
|
|
||||||
// Get the value of the request's Origin header.
|
// Add the "Vary: Access-Control-Request-Method" header.
|
||||||
|
w.Header().Add("Vary", "Access-Control-Request-Method")
|
||||||
|
|
||||||
origin := r.Header.Get("Origin")
|
origin := r.Header.Get("Origin")
|
||||||
|
|
||||||
// Only run this if there's an Origin request header present AND at least one
|
|
||||||
// trusted origin is configured.
|
|
||||||
if origin != "" && len(app.config.cors.trustedOrigins) != 0 {
|
if origin != "" && len(app.config.cors.trustedOrigins) != 0 {
|
||||||
// Loop through the list of trusted origins, checking to see if the request
|
|
||||||
// origin exactly matches one of them.
|
|
||||||
for i := range app.config.cors.trustedOrigins {
|
for i := range app.config.cors.trustedOrigins {
|
||||||
if origin == app.config.cors.trustedOrigins[i] {
|
if origin == app.config.cors.trustedOrigins[i] {
|
||||||
// If there is a match, then set a "Access-Control-Allow-Origin
|
|
||||||
// response header with the request origin as the value.
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||||
|
|
||||||
|
// Check if the request has the HTTP method OPTIONS and contains the
|
||||||
|
// "Access-Control-Request-Method" header. If it does, then we treat
|
||||||
|
// it as a preflight request.
|
||||||
|
if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" {
|
||||||
|
// Set the necessary preflight response headers, as discussed
|
||||||
|
// previously.
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "OPTIONS, PUT, PATCH, DELETE")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type")
|
||||||
|
|
||||||
|
// Write the headers along with a 200 OK status and return from
|
||||||
|
// the // the middleware with no further action.
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the next handler in the chain.
|
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"expvar"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
@@ -27,6 +28,8 @@ func (app *application) routes() http.Handler {
|
|||||||
|
|
||||||
router.HandlerFunc(http.MethodPost, "/v1/tokens/authentication",
|
router.HandlerFunc(http.MethodPost, "/v1/tokens/authentication",
|
||||||
app.createAuthenticationTokenHandler)
|
app.createAuthenticationTokenHandler)
|
||||||
|
// Register a new GET /debug/vars endpoint pointing to the expvar handler.
|
||||||
|
router.Handler(http.MethodGet, "/debug/vars", expvar.Handler())
|
||||||
|
|
||||||
return app.recoverPanic(app.enableCORS(app.rateLimit(app.authenticate(router))))
|
return app.recoverPanic(app.enableCORS(app.rateLimit(app.authenticate(router))))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const html = `
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: 'alice@example.com',
|
email: 'grace@example.com',
|
||||||
password: 'pa55word'
|
password: 'pa55word'
|
||||||
})
|
})
|
||||||
}).then(
|
}).then(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ http:
|
|||||||
"name": "Grace",
|
"name": "Grace",
|
||||||
"email": "grace@example.com",
|
"email": "grace@example.com",
|
||||||
"password": "pa55word"
|
"password": "pa55word"
|
||||||
|
|
||||||
}
|
}
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user