diff --git a/README.md b/README.md
index 1a2d59acbf7c1129e185ce34a8ca45fc0ca425be..91227a0095f6d43527ce5039653fc0dcc3c89cfd 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ import (
 
 func TestSlowResponse(t *testing.T) {
 	app := httpbin.New()
-	testServer := httptest.NewServer(app.Handler())
+	testServer := httptest.NewServer(app)
 	defer testServer.Close()
 
 	client := http.Client{
diff --git a/example_test.go b/example_test.go
index 2e7bdf0ccd396a103affe1e9c481d88488280740..811f78b7f2fb0a5c445c6ed16eeb7ae0c6756777 100644
--- a/example_test.go
+++ b/example_test.go
@@ -12,7 +12,7 @@ import (
 
 func TestSlowResponse(t *testing.T) {
 	app := httpbin.New()
-	testServer := httptest.NewServer(app.Handler())
+	testServer := httptest.NewServer(app)
 	defer testServer.Close()
 
 	client := http.Client{
diff --git a/examples/custom-instrumentation/main.go b/examples/custom-instrumentation/main.go
index 4415fc43ce435d88b2e0a56ccc8b7a155e7cea1b..f414e0bee3d965cbf03161fbe875506e81c7f8b1 100644
--- a/examples/custom-instrumentation/main.go
+++ b/examples/custom-instrumentation/main.go
@@ -13,12 +13,12 @@ import (
 func main() {
 	statsdClient, _ := statsd.New("")
 
-	h := httpbin.New(
+	app := httpbin.New(
 		httpbin.WithObserver(datadogObserver(statsdClient)),
 	)
 
 	listenAddr := "0.0.0.0:8080"
-	http.ListenAndServe(listenAddr, h.Handler())
+	http.ListenAndServe(listenAddr, app)
 }
 
 func datadogObserver(client statsd.ClientInterface) httpbin.Observer {
diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go
index 3b24fcd6e9caed562b1607b7232df6bd0907428e..5545db165805d6ac72deaa714fdb601f843b33c5 100644
--- a/httpbin/handlers_test.go
+++ b/httpbin/handlers_test.go
@@ -44,8 +44,6 @@ var app = New(
 	WithObserver(StdLogObserver(log.New(io.Discard, "", 0))),
 )
 
-var handler = app.Handler()
-
 func assertStatusCode(t *testing.T, w *httptest.ResponseRecorder, code int) {
 	t.Helper()
 	if w.Code != code {
@@ -93,7 +91,7 @@ func TestIndex(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, htmlContentType)
 	assertHeader(t, w, "Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' camo.githubusercontent.com")
@@ -104,7 +102,7 @@ func TestIndex__NotFound(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/foo", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 	assertStatusCode(t, w, http.StatusNotFound)
 }
 
@@ -112,7 +110,7 @@ func TestFormsPost(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/forms/post", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, htmlContentType)
 	assertBodyContains(t, w, `<form method="post" action="/post">`)
@@ -122,7 +120,7 @@ func TestUTF8(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/encoding/utf8", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, htmlContentType)
 	assertBodyContains(t, w, `Hello world, Καλημέρα κόσμε, コンニチハ`)
@@ -173,7 +171,7 @@ func TestGet(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("POST", "/get", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusMethodNotAllowed)
 		assertContentType(t, w, "text/plain; charset=utf-8")
@@ -219,7 +217,7 @@ func testRequestWithoutBody(t *testing.T, path string, params *url.Values, heade
 		}
 	}
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, expectedStatus)
 
@@ -251,7 +249,7 @@ func TestHead(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest(tc.verb, tc.path, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, tc.wantCode)
 
@@ -276,7 +274,7 @@ func TestCORS(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("GET", "/get", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		assertHeader(t, w, "Access-Control-Allow-Origin", "*")
 	})
 
@@ -285,7 +283,7 @@ func TestCORS(t *testing.T) {
 		r, _ := http.NewRequest("GET", "/get", nil)
 		r.Header.Set("Origin", "origin")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		assertHeader(t, w, "Access-Control-Allow-Origin", "origin")
 	})
 
@@ -293,7 +291,7 @@ func TestCORS(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("OPTIONS", "/get", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, 200)
 
@@ -317,7 +315,7 @@ func TestCORS(t *testing.T) {
 		r, _ := http.NewRequest("OPTIONS", "/get", nil)
 		r.Header.Set("Access-Control-Request-Headers", "X-Test-Header")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, 200)
 
@@ -371,7 +369,7 @@ func TestIP(t *testing.T) {
 				r.Header.Set(k, v)
 			}
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, http.StatusOK)
 			assertContentType(t, w, jsonContentType)
@@ -394,7 +392,7 @@ func TestUserAgent(t *testing.T) {
 	r, _ := http.NewRequest("GET", "/user-agent", nil)
 	r.Header.Set("User-Agent", "test")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -419,7 +417,7 @@ func TestHeaders(t *testing.T) {
 	r.Header.Add("Bar-Header", "bar1")
 	r.Header.Add("Bar-Header", "bar2")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -493,7 +491,7 @@ func TestAnything(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("HEAD", "/anything", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		assertStatusCode(t, w, http.StatusOK)
 		assertBodyEquals(t, w, "")
 		if contentLength := w.Header().Get("Content-Length"); contentLength != "" {
@@ -560,7 +558,7 @@ func testRequestWithBodyEmptyBody(t *testing.T, verb string, path string) {
 			r, _ := http.NewRequest(verb, path, nil)
 			r.Header.Set("Content-Type", test.contentType)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, http.StatusOK)
 			assertContentType(t, w, jsonContentType)
@@ -597,7 +595,7 @@ func testRequestWithBodyFormEncodedBody(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest(verb, path, strings.NewReader(params.Encode()))
 	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -631,7 +629,7 @@ func testRequestWithBodyHTML(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest(verb, path, strings.NewReader(data))
 	r.Header.Set("Content-Type", htmlContentType)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -653,7 +651,7 @@ func testRequestWithBodyFormEncodedBodyNoContentType(t *testing.T, verb, path st
 
 	r, _ := http.NewRequest(verb, path, strings.NewReader(params.Encode()))
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -701,7 +699,7 @@ func testRequestWithBodyMultiPartBody(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest(verb, path, bytes.NewReader(body.Bytes()))
 	r.Header.Set("Content-Type", mw.FormDataContentType())
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -733,7 +731,7 @@ func testRequestWithBodyInvalidFormEncodedBody(t *testing.T, verb, path string)
 	r, _ := http.NewRequest(verb, path, strings.NewReader("%ZZ"))
 	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 	assertStatusCode(t, w, http.StatusBadRequest)
 }
 
@@ -741,7 +739,7 @@ func testRequestWithBodyInvalidMultiPartBody(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest(verb, path, strings.NewReader("%ZZ"))
 	r.Header.Set("Content-Type", "multipart/form-data; etc")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 	assertStatusCode(t, w, http.StatusBadRequest)
 }
 
@@ -763,7 +761,7 @@ func testRequestWithBodyJSON(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest(verb, path, bytes.NewReader(inputBody))
 	r.Header.Set("Content-Type", "application/json; charset=utf-8")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -802,7 +800,7 @@ func testRequestWithBodyInvalidJSON(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest("POST", "/post", bytes.NewReader([]byte("foo")))
 	r.Header.Set("Content-Type", "application/json; charset=utf-8")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 	assertStatusCode(t, w, http.StatusBadRequest)
 }
 
@@ -811,7 +809,7 @@ func testRequestWithBodyBodyTooBig(t *testing.T, verb, path string) {
 
 	r, _ := http.NewRequest("POST", "/post", bytes.NewReader(body))
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusBadRequest)
 }
@@ -824,7 +822,7 @@ func testRequestWithBodyQueryParams(t *testing.T, verb, path string) {
 
 	r, _ := http.NewRequest("POST", fmt.Sprintf("/post?%s", params.Encode()), nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -861,7 +859,7 @@ func testRequestWithBodyQueryParamsAndBody(t *testing.T, verb, path string) {
 	r, _ := http.NewRequest("POST", url, body)
 	r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -935,7 +933,7 @@ func TestStatus(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", fmt.Sprintf("/status/%d", test.code), nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, test.code)
 
@@ -970,7 +968,7 @@ func TestStatus(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.status)
 		})
 	}
@@ -982,7 +980,7 @@ func TestUnstable(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("GET", "/unstable", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		if w.Code != 200 && w.Code != 500 {
 			t.Fatalf("expected status code 200 or 500, got %d", w.Code)
 		}
@@ -1002,7 +1000,7 @@ func TestUnstable(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.status)
 		})
 	}
@@ -1017,7 +1015,7 @@ func TestUnstable(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			if w.Code != 200 && w.Code != 500 {
 				t.Fatalf("expected status code 200 or 500, got %d", w.Code)
 			}
@@ -1039,7 +1037,7 @@ func TestUnstable(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusBadRequest)
 		})
 	}
@@ -1061,7 +1059,7 @@ func TestResponseHeaders__OK(t *testing.T) {
 
 	r, _ := http.NewRequest("GET", fmt.Sprintf("/response-headers?%s", params.Encode()), nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, jsonContentType)
@@ -1102,7 +1100,7 @@ func TestResponseHeaders__OverrideContentType(t *testing.T) {
 
 	r, _ := http.NewRequest("GET", fmt.Sprintf("/response-headers?%s", params.Encode()), nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 	assertContentType(t, w, contentType)
@@ -1142,7 +1140,7 @@ func TestRedirects(t *testing.T) {
 			r, _ := http.NewRequest("GET", test.requestURL, nil)
 			r.Host = "host"
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, http.StatusFound)
 			assertHeader(t, w, "Location", test.expectedLocation)
@@ -1178,7 +1176,7 @@ func TestRedirects(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.requestURL, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, test.expectedStatus)
 		})
@@ -1207,7 +1205,7 @@ func TestRedirectTo(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, test.expectedStatus)
 			assertHeader(t, w, "Location", test.expectedLocation)
@@ -1230,7 +1228,7 @@ func TestRedirectTo(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, test.expectedStatus)
 		})
@@ -1274,7 +1272,7 @@ func TestCookies(t *testing.T) {
 			})
 		}
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, jsonContentType)
@@ -1318,7 +1316,7 @@ func TestSetCookies(t *testing.T) {
 
 	r, _ := http.NewRequest("GET", fmt.Sprintf("/cookies/set?%s", params.Encode()), nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusFound)
 	assertHeader(t, w, "Location", "/cookies")
@@ -1353,7 +1351,7 @@ func TestDeleteCookies(t *testing.T) {
 		})
 	}
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusFound)
 	assertHeader(t, w, "Location", "/cookies")
@@ -1374,7 +1372,7 @@ func TestBasicAuth(t *testing.T) {
 		r, _ := http.NewRequest("GET", "/basic-auth/user/pass", nil)
 		r.SetBasicAuth("user", "pass")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, jsonContentType)
@@ -1395,7 +1393,7 @@ func TestBasicAuth(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("GET", "/basic-auth/user/pass", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusUnauthorized)
 		assertContentType(t, w, jsonContentType)
@@ -1418,7 +1416,7 @@ func TestBasicAuth(t *testing.T) {
 		r, _ := http.NewRequest("GET", "/basic-auth/user/pass", nil)
 		r.SetBasicAuth("bad", "auth")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusUnauthorized)
 		assertContentType(t, w, jsonContentType)
@@ -1451,7 +1449,7 @@ func TestBasicAuth(t *testing.T) {
 			r, _ := http.NewRequest("GET", test.url, nil)
 			r.SetBasicAuth("foo", "bar")
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.status)
 		})
 	}
@@ -1464,7 +1462,7 @@ func TestHiddenBasicAuth(t *testing.T) {
 		r, _ := http.NewRequest("GET", "/hidden-basic-auth/user/pass", nil)
 		r.SetBasicAuth("user", "pass")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, jsonContentType)
@@ -1485,7 +1483,7 @@ func TestHiddenBasicAuth(t *testing.T) {
 		t.Parallel()
 		r, _ := http.NewRequest("GET", "/hidden-basic-auth/user/pass", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusNotFound)
 		if w.Header().Get("WWW-Authenticate") != "" {
@@ -1498,7 +1496,7 @@ func TestHiddenBasicAuth(t *testing.T) {
 		r, _ := http.NewRequest("GET", "/hidden-basic-auth/user/pass", nil)
 		r.SetBasicAuth("bad", "auth")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusNotFound)
 		if w.Header().Get("WWW-Authenticate") != "" {
@@ -1521,7 +1519,7 @@ func TestHiddenBasicAuth(t *testing.T) {
 			r, _ := http.NewRequest("GET", test.url, nil)
 			r.SetBasicAuth("foo", "bar")
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.status)
 		})
 	}
@@ -1553,7 +1551,7 @@ func TestDigestAuth(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.status)
 		})
 	}
@@ -1577,7 +1575,7 @@ func TestDigestAuth(t *testing.T) {
 		r.RequestURI = url
 		r.Header.Set("Authorization", authorization)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 
@@ -1598,7 +1596,7 @@ func TestGzip(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/gzip", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, "application/json; encoding=utf-8")
 	assertHeader(t, w, "Content-Encoding", "gzip")
@@ -1641,7 +1639,7 @@ func TestDeflate(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/deflate", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, "application/json; encoding=utf-8")
 	assertHeader(t, w, "Content-Encoding", "deflate")
@@ -1699,7 +1697,7 @@ func TestStream(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			// TODO: The stdlib seems to automagically unchunk these responses
 			// and I'm not quite sure how to test this:
@@ -1747,7 +1745,7 @@ func TestStream(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.code)
 		})
 	}
@@ -1776,7 +1774,7 @@ func TestDelay(t *testing.T) {
 
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			elapsed := time.Since(start)
 
@@ -1797,7 +1795,7 @@ func TestDelay(t *testing.T) {
 
 	t.Run("handle cancelation", func(t *testing.T) {
 		t.Parallel()
-		srv := httptest.NewServer(handler)
+		srv := httptest.NewServer(app)
 		defer srv.Close()
 
 		client := http.Client{
@@ -1816,7 +1814,7 @@ func TestDelay(t *testing.T) {
 
 		r, _ := http.NewRequestWithContext(ctx, "GET", "/delay/1s", nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		if w.Code != 499 {
 			t.Errorf("expected 499 response, got %d", w.Code)
@@ -1844,7 +1842,7 @@ func TestDelay(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.code)
 		})
 	}
@@ -1895,7 +1893,7 @@ func TestDrip(t *testing.T) {
 
 			r, _ := http.NewRequest("GET", url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			elapsed := time.Since(start)
 
@@ -1914,7 +1912,7 @@ func TestDrip(t *testing.T) {
 
 	t.Run("handle cancelation during initial delay", func(t *testing.T) {
 		t.Parallel()
-		srv := httptest.NewServer(handler)
+		srv := httptest.NewServer(app)
 		defer srv.Close()
 
 		// For this test, we expect the client to time out and cancel the
@@ -1945,7 +1943,7 @@ func TestDrip(t *testing.T) {
 
 	t.Run("handle cancelation during drip", func(t *testing.T) {
 		t.Parallel()
-		srv := httptest.NewServer(handler)
+		srv := httptest.NewServer(app)
 		defer srv.Close()
 
 		client := http.Client{
@@ -2004,14 +2002,14 @@ func TestDrip(t *testing.T) {
 
 			r, _ := http.NewRequest("GET", url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.code)
 		})
 	}
 
 	t.Run("ensure HEAD request works with streaming responses", func(t *testing.T) {
 		t.Parallel()
-		srv := httptest.NewServer(handler)
+		srv := httptest.NewServer(app)
 		defer srv.Close()
 
 		resp, err := http.Head(srv.URL + "/drip?duration=900ms&delay=100ms")
@@ -2042,7 +2040,7 @@ func TestRange(t *testing.T) {
 		url := fmt.Sprintf("/range/%d", wantBytes)
 		r, _ := http.NewRequest("GET", url, nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertHeader(t, w, "ETag", fmt.Sprintf("range%d", wantBytes))
@@ -2061,7 +2059,7 @@ func TestRange(t *testing.T) {
 		r, _ := http.NewRequest("GET", url, nil)
 		r.Header.Add("Range", "bytes=10-24")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusPartialContent)
 		assertHeader(t, w, "ETag", "range100")
@@ -2077,7 +2075,7 @@ func TestRange(t *testing.T) {
 		r, _ := http.NewRequest("GET", url, nil)
 		r.Header.Add("Range", "bytes=0-15")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusPartialContent)
 		assertHeader(t, w, "ETag", "range1000")
@@ -2093,7 +2091,7 @@ func TestRange(t *testing.T) {
 		r, _ := http.NewRequest("GET", url, nil)
 		r.Header.Add("Range", "bytes=20-")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusPartialContent)
 		assertHeader(t, w, "ETag", "range26")
@@ -2108,7 +2106,7 @@ func TestRange(t *testing.T) {
 		r, _ := http.NewRequest("GET", url, nil)
 		r.Header.Add("Range", "bytes=-5")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		t.Logf("headers = %v", w.Header())
 		assertStatusCode(t, w, http.StatusPartialContent)
@@ -2124,7 +2122,7 @@ func TestRange(t *testing.T) {
 		r, _ := http.NewRequest("GET", url, nil)
 		r.Header.Add("Range", "bytes=-5")
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusPartialContent)
 		assertHeader(t, w, "ETag", "range26")
@@ -2149,7 +2147,7 @@ func TestRange(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusOK)
 			assertBodyEquals(t, w, "abcdefghijklmnopqrstuvwxyz")
 		})
@@ -2173,7 +2171,7 @@ func TestRange(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.code)
 		})
 	}
@@ -2183,7 +2181,7 @@ func TestHTML(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/html", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, htmlContentType)
 	assertBodyContains(t, w, `<h1>Herman Melville - Moby-Dick</h1>`)
@@ -2193,7 +2191,7 @@ func TestRobots(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/robots.txt", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, "text/plain")
 	assertBodyContains(t, w, `Disallow: /deny`)
@@ -2203,7 +2201,7 @@ func TestDeny(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/deny", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, "text/plain")
 	assertBodyContains(t, w, `YOU SHOULDN'T BE HERE`)
@@ -2216,7 +2214,7 @@ func TestCache(t *testing.T) {
 		url := "/cache"
 		r, _ := http.NewRequest("GET", url, nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, jsonContentType)
@@ -2252,7 +2250,7 @@ func TestCache(t *testing.T) {
 			r, _ := http.NewRequest("GET", "/cache", nil)
 			r.Header.Add(test.headerKey, test.headerVal)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusNotModified)
 		})
 	}
@@ -2265,7 +2263,7 @@ func TestCacheControl(t *testing.T) {
 		url := "/cache/60"
 		r, _ := http.NewRequest("GET", url, nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, jsonContentType)
@@ -2286,7 +2284,7 @@ func TestCacheControl(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.expectedStatus)
 		})
 	}
@@ -2299,7 +2297,7 @@ func TestETag(t *testing.T) {
 		url := "/etag/abc"
 		r, _ := http.NewRequest("GET", url, nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		assertStatusCode(t, w, http.StatusOK)
 		assertHeader(t, w, "ETag", `"abc"`)
 	})
@@ -2330,7 +2328,7 @@ func TestETag(t *testing.T) {
 			r, _ := http.NewRequest("GET", url, nil)
 			r.Header.Add(test.headerKey, test.headerVal)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.expectedStatus)
 		})
 	}
@@ -2347,7 +2345,7 @@ func TestETag(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.expectedStatus)
 		})
 	}
@@ -2360,7 +2358,7 @@ func TestBytes(t *testing.T) {
 		url := "/bytes/1024"
 		r, _ := http.NewRequest("GET", url, nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, "application/octet-stream")
@@ -2374,7 +2372,7 @@ func TestBytes(t *testing.T) {
 		url := "/bytes/16?seed=1234567890"
 		r, _ := http.NewRequest("GET", url, nil)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 		assertContentType(t, w, "application/octet-stream")
@@ -2402,7 +2400,7 @@ func TestBytes(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusOK)
 			assertHeader(t, w, "Content-Length", fmt.Sprintf("%d", test.expectedContentLength))
 			if len(w.Body.Bytes()) != test.expectedContentLength {
@@ -2431,7 +2429,7 @@ func TestBytes(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.expectedStatus)
 		})
 	}
@@ -2460,7 +2458,7 @@ func TestStreamBytes(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			// TODO: The stdlib seems to automagically unchunk these responses
 			// and I'm not quite sure how to test this:
@@ -2496,7 +2494,7 @@ func TestStreamBytes(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.code)
 		})
 	}
@@ -2518,7 +2516,7 @@ func TestLinks(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, http.StatusFound)
 			assertHeader(t, w, "Location", test.expectedLocation)
@@ -2547,7 +2545,7 @@ func TestLinks(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, test.expectedStatus)
 		})
@@ -2571,7 +2569,7 @@ func TestLinks(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, http.StatusOK)
 			assertContentType(t, w, htmlContentType)
@@ -2606,7 +2604,7 @@ func TestImage(t *testing.T) {
 			r, _ := http.NewRequest("GET", "/image", nil)
 			r.Header.Set("Accept", test.acceptHeader)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 
 			assertStatusCode(t, w, test.expectedStatus)
 			if test.expectedContentType != "" {
@@ -2635,7 +2633,7 @@ func TestImage(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, test.expectedStatus)
 		})
 	}
@@ -2645,7 +2643,7 @@ func TestXML(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/xml", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, "application/xml")
 	assertBodyContains(t, w, `<?xml version='1.0' encoding='us-ascii'?>`)
@@ -2666,7 +2664,7 @@ func TestUUID(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/uuid", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertStatusCode(t, w, http.StatusOK)
 
@@ -2709,7 +2707,7 @@ func TestBase64(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.requestURL, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusOK)
 			assertContentType(t, w, "text/plain")
 			assertBodyEquals(t, w, test.want)
@@ -2764,7 +2762,7 @@ func TestBase64(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.requestURL, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusBadRequest)
 			assertBodyContains(t, w, test.expectedBodyContains)
 		})
@@ -2775,7 +2773,7 @@ func TestJSON(t *testing.T) {
 	t.Parallel()
 	r, _ := http.NewRequest("GET", "/json", nil)
 	w := httptest.NewRecorder()
-	handler.ServeHTTP(w, r)
+	app.ServeHTTP(w, r)
 
 	assertContentType(t, w, jsonContentType)
 	assertBodyContains(t, w, `Wake up to WonderWidgets!`)
@@ -2791,7 +2789,7 @@ func TestBearer(t *testing.T) {
 		r, _ := http.NewRequest("GET", requestURL, nil)
 		r.Header.Set("Authorization", "Bearer "+token)
 		w := httptest.NewRecorder()
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 
 		assertStatusCode(t, w, http.StatusOK)
 
@@ -2842,7 +2840,7 @@ func TestBearer(t *testing.T) {
 				r.Header.Set("Authorization", test.authorizationHeader)
 			}
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertHeader(t, w, "WWW-Authenticate", "Bearer")
 			assertStatusCode(t, w, http.StatusUnauthorized)
 		})
@@ -2862,7 +2860,7 @@ func TestNotImplemented(t *testing.T) {
 			t.Parallel()
 			r, _ := http.NewRequest("GET", test.url, nil)
 			w := httptest.NewRecorder()
-			handler.ServeHTTP(w, r)
+			app.ServeHTTP(w, r)
 			assertStatusCode(t, w, http.StatusNotImplemented)
 		})
 	}
@@ -2882,11 +2880,11 @@ func TestHostname(t *testing.T) {
 	t.Run("default hostname", func(t *testing.T) {
 		t.Parallel()
 		var (
-			handler = New().Handler()
-			r, _    = http.NewRequest("GET", "/hostname", nil)
-			w       = httptest.NewRecorder()
+			app  = New()
+			r, _ = http.NewRequest("GET", "/hostname", nil)
+			w    = httptest.NewRecorder()
 		)
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		assertStatusCode(t, w, http.StatusOK)
 		resp := loadResponse(t, w.Body.Bytes())
 		if resp.Hostname != DefaultHostname {
@@ -2898,11 +2896,11 @@ func TestHostname(t *testing.T) {
 		t.Parallel()
 		var (
 			realHostname = "real-hostname"
-			handler      = New(WithHostname(realHostname)).Handler()
+			app          = New(WithHostname(realHostname))
 			r, _         = http.NewRequest("GET", "/hostname", nil)
 			w            = httptest.NewRecorder()
 		)
-		handler.ServeHTTP(w, r)
+		app.ServeHTTP(w, r)
 		assertStatusCode(t, w, http.StatusOK)
 		resp := loadResponse(t, w.Body.Bytes())
 		if resp.Hostname != realHostname {
diff --git a/httpbin/httpbin.go b/httpbin/httpbin.go
index 4d5c85e7267e9dcfd9f5651618c51067afff27ce..6140d27bbcce0725e043513539fce6f7c3a31c7f 100644
--- a/httpbin/httpbin.go
+++ b/httpbin/httpbin.go
@@ -106,6 +106,9 @@ type HTTPBin struct {
 
 	// The hostname to expose via /hostname.
 	hostname string
+
+	// The app's http handler
+	handler http.Handler
 }
 
 // DefaultParams defines default parameter values
@@ -236,9 +239,18 @@ func New(opts ...OptionFunc) *HTTPBin {
 	for _, opt := range opts {
 		opt(h)
 	}
+	h.handler = h.Handler()
 	return h
 }
 
+// ServeHTTP implememnts the http.Handler interface.
+func (h *HTTPBin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	h.handler.ServeHTTP(w, r)
+}
+
+// Assert that HTTPBin implements http.Handler interface
+var _ http.Handler = &HTTPBin{}
+
 // OptionFunc uses the "functional options" pattern to customize an HTTPBin
 // instance
 type OptionFunc func(*HTTPBin)