internal/frontend: factor out serve json logic

Logic for serving a JSON page is factored out into the functions
fetchJSONPage, shouldServeJSON, and serveJSONPage. This will be reused
for search tests in a later CL.

For golang/go#44142

Change-Id: I253933f2c7911e140660a0cc617491ed42438b45
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/346412
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/internal/frontend/client.go b/internal/frontend/client.go
index 008af35..3368eb2 100644
--- a/internal/frontend/client.go
+++ b/internal/frontend/client.go
@@ -42,16 +42,7 @@
 func (c *Client) GetVersions(pkgPath string) (_ *VersionsDetails, err error) {
 	defer derrors.Wrap(&err, "GetVersions(%q)", pkgPath)
 	u := fmt.Sprintf("%s/%s?tab=versions&content=json", c.url, pkgPath)
-	r, err := c.httpClient.Get(u)
-	if err != nil {
-		return nil, err
-	}
-	defer r.Body.Close()
-	if r.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf(r.Status)
-	}
-
-	body, err := ioutil.ReadAll(r.Body)
+	body, err := c.fetchJSONPage(u)
 	if err != nil {
 		return nil, err
 	}
@@ -61,3 +52,39 @@
 	}
 	return &vd, nil
 }
+
+func (c *Client) fetchJSONPage(url string) (_ []byte, err error) {
+	defer derrors.Wrap(&err, "fetchJSONPage(%q)", url)
+	r, err := c.httpClient.Get(url)
+	if err != nil {
+		return nil, err
+	}
+	defer r.Body.Close()
+	if r.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf(r.Status)
+	}
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return nil, err
+	}
+	return body, nil
+}
+
+func (s *Server) shouldServeJSON(r *http.Request) bool {
+	return s.serveStats && r.FormValue("content") == "json"
+}
+
+func (s *Server) serveJSONPage(w http.ResponseWriter, r *http.Request, d interface{}) (err error) {
+	defer derrors.Wrap(&err, "serveJSONPage(ctx, w, r)")
+	if !s.shouldServeJSON(r) {
+		return derrors.NotFound
+	}
+	data, err := json.Marshal(d)
+	if err != nil {
+		return fmt.Errorf("json.Marshal: %v", err)
+	}
+	if _, err := w.Write(data); err != nil {
+		return fmt.Errorf("w.Write: %v", err)
+	}
+	return nil
+}
diff --git a/internal/frontend/unit.go b/internal/frontend/unit.go
index 1fc7f8a..5d66d40 100644
--- a/internal/frontend/unit.go
+++ b/internal/frontend/unit.go
@@ -6,7 +6,6 @@
 
 import (
 	"context"
-	"encoding/json"
 	"errors"
 	"fmt"
 	"net/http"
@@ -123,15 +122,8 @@
 	if err != nil {
 		return err
 	}
-	if s.serveStats && r.FormValue("content") == "json" {
-		data, err := json.Marshal(d)
-		if err != nil {
-			return fmt.Errorf("json.Marshal: %v", err)
-		}
-		if _, err := w.Write(data); err != nil {
-			return fmt.Errorf("w.Write: %v", err)
-		}
-		return nil
+	if s.shouldServeJSON(r) {
+		return s.serveJSONPage(w, r, d)
 	}
 
 	recordVersionTypeMetric(ctx, info.requestedVersion)