diff --git a/helpers.go b/helpers.go
new file mode 100644
index 0000000000000000000000000000000000000000..7b9cbb5d649d94c93a8928ba602746309af194d9
--- /dev/null
+++ b/helpers.go
@@ -0,0 +1,64 @@
+package main
+
+import (
+	"encoding/json"
+	"log"
+
+	"net/http"
+	"net/url"
+)
+
+func getOrigin(r *http.Request) string {
+	origin := r.Header.Get("X-Forwarded-For")
+	if origin == "" {
+		origin = r.RemoteAddr
+	}
+	return origin
+}
+
+func getURL(r *http.Request) string {
+	scheme := r.Header.Get("X-Forwarded-Proto")
+	if scheme == "" {
+		scheme = r.Header.Get("X-Forwarded-Protocol")
+	}
+	if scheme == "" && r.Header.Get("X-Forwarded-Ssl") == "on" {
+		scheme = "https"
+	}
+	if scheme == "" {
+		scheme = "http"
+	}
+
+	host := r.URL.Host
+	if host == "" {
+		host = r.Host
+	}
+
+	u := &url.URL{
+		Scheme:     scheme,
+		Opaque:     r.URL.Opaque,
+		User:       r.URL.User,
+		Host:       host,
+		Path:       r.URL.Path,
+		RawPath:    r.URL.RawPath,
+		ForceQuery: r.URL.ForceQuery,
+		RawQuery:   r.URL.RawQuery,
+		Fragment:   r.URL.Fragment,
+	}
+	return u.String()
+}
+
+func writeResponse(w http.ResponseWriter, r *http.Request, resp *Resp) {
+	resp.Origin = getOrigin(r)
+	resp.URL = getURL(r)
+
+	body, err := json.Marshal(resp)
+	if err != nil {
+		log.Printf("error marshalling %v as JSON: %s", resp, err)
+	}
+	writeJSON(w, body)
+}
+
+func writeJSON(w http.ResponseWriter, body []byte) {
+	w.Header().Set("Content-Type", "application/json; encoding=utf-8")
+	w.Write(body)
+}
diff --git a/main.go b/main.go
index 005dbf38c635641b26a81290117e7b64dedef626..4ddfda6eb904a3d2bdf14d09721928675ea2902f 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"encoding/json"
 	"fmt"
 	"html/template"
 	"log"
@@ -22,84 +21,6 @@ type Resp struct {
 	JSON  map[string][]string `json:"json,omitempty"`
 }
 
-func getOrigin(r *http.Request) string {
-	origin := r.Header.Get("X-Forwarded-For")
-	if origin == "" {
-		origin = r.RemoteAddr
-	}
-	return origin
-}
-
-func getURL(r *http.Request) string {
-	scheme := r.Header.Get("X-Forwarded-Proto")
-	if scheme == "" {
-		scheme = r.Header.Get("X-Forwarded-Protocol")
-	}
-	if scheme == "" && r.Header.Get("X-Forwarded-Ssl") == "on" {
-		scheme = "https"
-	}
-	if scheme == "" {
-		scheme = "http"
-	}
-
-	host := r.URL.Host
-	if host == "" {
-		host = r.Host
-	}
-
-	u := &url.URL{
-		Scheme:     scheme,
-		Opaque:     r.URL.Opaque,
-		User:       r.URL.User,
-		Host:       host,
-		Path:       r.URL.Path,
-		RawPath:    r.URL.RawPath,
-		ForceQuery: r.URL.ForceQuery,
-		RawQuery:   r.URL.RawQuery,
-		Fragment:   r.URL.Fragment,
-	}
-	return u.String()
-}
-
-func writeResponse(w http.ResponseWriter, r *http.Request, resp *Resp) {
-	resp.Origin = getOrigin(r)
-	resp.URL = getURL(r)
-
-	body, err := json.Marshal(resp)
-	if err != nil {
-		log.Printf("error marshalling %v as JSON: %s", resp, err)
-	}
-	w.Write(body)
-}
-
-func logger(h http.Handler) http.Handler {
-	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		h.ServeHTTP(w, r)
-		log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
-	})
-}
-
-func cors(h http.Handler) http.Handler {
-	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		origin := r.Header.Get("Origin")
-		if origin == "" {
-			origin = "*"
-		}
-		respHeader := w.Header()
-		respHeader.Set("Access-Control-Allow-Origin", origin)
-		respHeader.Set("Access-Control-Allow-Credentials", "true")
-
-		if r.Method == "OPTIONS" {
-			respHeader.Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
-			respHeader.Set("Access-Control-Max-Age", "3600")
-			if r.Header.Get("Access-Control-Request-Headers") != "" {
-				respHeader.Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))
-			}
-		}
-		h.ServeHTTP(w, r)
-	})
-}
-
 func index(w http.ResponseWriter, r *http.Request) {
 	t, err := template.ParseGlob("templates/*.html")
 	if err != nil {
diff --git a/middleware.go b/middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..c25e383386db61bc71861c462ae1392c4e075da2
--- /dev/null
+++ b/middleware.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+	"log"
+	"net/http"
+)
+
+func logger(h http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		h.ServeHTTP(w, r)
+		log.Printf("%s %s %s", r.RemoteAddr, r.Method, r.URL)
+	})
+}
+
+func cors(h http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		origin := r.Header.Get("Origin")
+		if origin == "" {
+			origin = "*"
+		}
+		respHeader := w.Header()
+		respHeader.Set("Access-Control-Allow-Origin", origin)
+		respHeader.Set("Access-Control-Allow-Credentials", "true")
+
+		if r.Method == "OPTIONS" {
+			respHeader.Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
+			respHeader.Set("Access-Control-Max-Age", "3600")
+			if r.Header.Get("Access-Control-Request-Headers") != "" {
+				respHeader.Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))
+			}
+		}
+		h.ServeHTTP(w, r)
+	})
+}