# Middleware

This page shows how to wire go-ip-sentry into Gin or `net/http`, how to skip specific paths, and how to call `Check` directly without middleware.

## Three Ways to Integrate

| Option | Signature | On failure |
|---|---|---|
| `HTTPMiddleware` | `func (i *IPGuardian) HTTPMiddleware(next http.Handler) http.Handler` | Sets `Content-Type: application/json`, writes the status and `{"error": "..."}`, and skips `next` |
| `GinMiddleware` | `func (i *IPGuardian) GinMiddleware() gin.HandlerFunc` | `c.JSON(status, gin.H{"error": ...})` then `c.Abort()` |
| `Check` | `func (i *IPGuardian) Check(r *http.Request, w http.ResponseWriter) IPGuardianResult` | Up to the caller |

All three have already written the session and device cookies when they pass, so they must run before the handler writes a body.

## net/http

```go
mux := http.NewServeMux()
mux.HandleFunc("/api/orders", ordersHandler)

log.Fatal(http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", sentry.HTTPMiddleware(mux)))
```

## Gin

```go
r := gin.New()
r.Use(gin.Recovery())

api := r.Group("/api")
api.Use(sentry.GinMiddleware())
api.GET("/orders", listOrders)

if err := r.RunTLS(":8443", "cert.pem", "key.pem"); err != nil {
	log.Fatal(err)
}
```

Keep `gin.Recovery()`: when Redis fails during scoring, `Check` panics (see [Known Issues](/known-issues)), and Recovery turns that into a `500`.

## Skipping Paths

Health checks, metrics scrapes, and fixed-period polling build up regular intervals and rate counts, so keep them out:

```go
func protect(sentry *golangIPSentry.IPGuardian, next http.Handler) http.Handler {
	guarded := sentry.HTTPMiddleware(next)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case "/healthz", "/metrics":
			next.ServeHTTP(w, r)
		default:
			guarded.ServeHTTP(w, r)
		}
	})
}
```

## Calling Check Directly

When you need a custom response format (an HTML error page, for example):

```go
func handler(sentry *golangIPSentry.IPGuardian) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		result := sentry.Check(r, w)
		if !result.Success {
			http.Error(w, http.StatusText(result.StatusCode), result.StatusCode)
			return
		}
		w.Write([]byte("OK"))
	}
}
```

`IPGuardianResult.Error` contains the client IP; check your privacy requirements before echoing it back to clients.
