diff controllers/json.go @ 237:3771788d3dae

Reduce boilerplate code when writing JSON parsing/generating endpoints.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 26 Jul 2018 17:07:03 +0200
parents
children 2b39bf2bf1fd
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/controllers/json.go	Thu Jul 26 17:07:03 2018 +0200
@@ -0,0 +1,94 @@
+package controllers
+
+import (
+	"database/sql"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+
+	"gemma.intevation.de/gemma/auth"
+	"github.com/jackc/pgx"
+)
+
+type JSONResult struct {
+	Code   int
+	Result interface{}
+}
+
+type JSONHandler struct {
+	Input   func() interface{}
+	Process func(http.ResponseWriter, *http.Request, interface{}, *sql.DB) (JSONResult, error)
+}
+
+type JSONError struct {
+	Code    int
+	Message string
+}
+
+func (je JSONError) Error() string {
+	return fmt.Sprintf("%d: %s", je.Code, je.Message)
+}
+
+func (j *JSONHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
+
+	var input interface{}
+	if j.Input != nil {
+		input = j.Input()
+		defer req.Body.Close()
+		if err := json.NewDecoder(req.Body).Decode(input); err != nil {
+			http.Error(rw, "error: "+err.Error(), http.StatusBadRequest)
+			return
+		}
+	}
+
+	token, _ := auth.GetToken(req)
+	var jr JSONResult
+	err := auth.ConnPool.Do(token, func(db *sql.DB) (err error) {
+		jr, err = j.Process(rw, req, input, db)
+		return err
+	})
+
+	if err != nil {
+		switch e := err.(type) {
+		case pgx.PgError:
+			var res = struct {
+				Result  string `json:"result"`
+				Code    string `json:"code,omitempty"`
+				Message string `json:"message,omitempty"`
+			}{
+				Result:  "failure",
+				Code:    e.Code,
+				Message: e.Message,
+			}
+			rw.Header().Set("Content-Type", "application/json")
+			rw.WriteHeader(http.StatusInternalServerError)
+			if err := json.NewEncoder(rw).Encode(&res); err != nil {
+				log.Printf("error: %v\n", err)
+			}
+		case JSONError:
+			rw.Header().Set("Content-Type", "application/json")
+			rw.WriteHeader(http.StatusInternalServerError)
+			var res = struct {
+				Message string `json:"message"`
+			}{
+				Message: e.Message,
+			}
+			if err := json.NewEncoder(rw).Encode(&res); err != nil {
+				log.Printf("error: %v\n", err)
+			}
+		default:
+			log.Printf("err: %v\n", err)
+			http.Error(rw,
+				"error: "+err.Error(),
+				http.StatusInternalServerError)
+		}
+		return
+	}
+
+	rw.Header().Set("Content-Type", "application/json")
+	rw.WriteHeader(jr.Code)
+	if err := json.NewEncoder(rw).Encode(jr.Result); err != nil {
+		log.Printf("error: %v\n", err)
+	}
+}