github.com/d0sbit/gocode@v0.0.0-20211001144653-a968ce917518/cmd/gocode_handlercrud/handlercrud.tmpl (about)

     1  {{define "HandlerUtil"}}
     2  import "net/http"
     3  import "strings"
     4  import "strconv"
     5  import "encoding/json"
     6  import "fmt"
     7  import "time"
     8  import "log"
     9  import "errors"
    10  import "runtime"
    11  import mathrand "math/rand"
    12  import "github.com/julienschmidt/httprouter"
    13  
    14  const (
    15      Create = "create"
    16      Read = "read"
    17      Update = "update"
    18      Delete = "delete"
    19  )
    20  
    21  type Allower interface {
    22      Allow(obj interface{}, perm string) error
    23  }
    24  
    25  type AllowerFunc func(obj interface{}, perm string) error
    26  
    27  func (f AllowerFunc) Allow(obj interface{}, perm string) error {
    28      return f(obj, perm)
    29  }
    30  
    31  func isJSONMimeType(mt string) bool {
    32      mt = strings.TrimSpace(strings.SplitN(mt, ";", 2)[0])
    33      if strings.EqualFold("application/json", mt) {
    34          return true
    35      }
    36      return false
    37  }
    38  
    39  func param(r *http.Request, names ...string) string {
    40      p := httprouter.ParamsFromContext(r.Context())
    41      for _, name := range names {
    42          value := p.ByName(name)
    43          if value != "" {
    44              return value
    45          }
    46          value = r.FormValue(name)
    47          if value != "" {
    48              return value
    49          }
    50      }
    51      return ""
    52  }
    53  
    54  func scanParam(dst interface{}, paramVal string) (err error) {
    55  
    56      // some common cases we can deal with simply
    57      switch dstv := dst.(type) {
    58      case *string:
    59          *dstv = paramVal
    60          return
    61      case *int:
    62          v, err := strconv.ParseInt(paramVal, 0, 0)
    63          if err != nil {
    64              return err
    65          }
    66          *dstv = int(v)
    67          return nil
    68      case *uint:
    69          v, err := strconv.ParseUint(paramVal, 0, 0)
    70          if err != nil {
    71              return err
    72          }
    73          *dstv = uint(v)
    74          return nil
    75      case *int64:
    76          *dstv, err = strconv.ParseInt(paramVal, 0, 64)
    77          return nil
    78      case *uint64:
    79          *dstv, err = strconv.ParseUint(paramVal, 0, 64)
    80          return nil
    81      case *int32:
    82          v, err := strconv.ParseInt(paramVal, 0, 32)
    83          if err != nil {
    84              return err
    85          }
    86          *dstv = int32(v)
    87          return nil
    88      case *uint32:
    89          v, err := strconv.ParseUint(paramVal, 0, 32)
    90          if err != nil {
    91              return err
    92          }
    93          *dstv = uint32(v)
    94          return nil
    95      }
    96  
    97      // or delegate to a JSON unmarshal func if available
    98      if j, ok := dst.(json.Unmarshaler); ok {
    99          // TODO: read json.Marshal source to see if it's worth adding a fast path for strings that don't need escaping
   100          b, err := json.Marshal(paramVal)
   101          if err != nil {
   102              return err
   103          }
   104          return j.UnmarshalJSON(b)
   105      }
   106  
   107      return fmt.Errorf("don't know how to scan into %T", dst)
   108  }
   109  
   110  type httpStatusCoder interface {
   111      HTTPStatusCode() int
   112  }
   113  
   114  var rnd = mathrand.New(mathrand.NewSource(time.Now().UnixNano()))
   115  
   116  type printfer interface {
   117      Printf(format string, v ...interface{})
   118  }
   119  
   120  var logger printfer = log.Default()
   121  
   122  func writeErrf(w http.ResponseWriter, status int, err error, responseTextFormat string, args ...interface{}) {
   123  
   124      // look for a httpStatusCoder or default to status 500 (internal server error)
   125      sterr := err
   126      for status <= 0 && sterr != nil {
   127          s, ok := sterr.(httpStatusCoder)
   128          if ok {
   129              status = s.HTTPStatusCode()
   130              break
   131          }
   132          sterr = errors.Unwrap(sterr)
   133      }
   134      if status <= 0 {
   135          status = 500
   136      }
   137  
   138      errID := fmt.Sprintf("%016x", rnd.Uint64())
   139  
   140      w.Header().Set("X-Error-Id", errID)
   141      w.Header().Set("Content-Type", "text/html; charset=utf-8")
   142  
   143      w.WriteHeader(status)
   144  
   145      var responseMessage string
   146      if responseTextFormat != "" {
   147          responseMessage = fmt.Sprintf(responseTextFormat, args...)
   148      }
   149      if responseMessage == "" {
   150          responseMessage = http.StatusText(status)
   151      }
   152      if responseMessage == "" {
   153          responseMessage = "unknown error"
   154      }
   155  
   156      fmt.Fprint(w, "<h1>")
   157      fmt.Fprint(w, responseMessage)
   158      fmt.Fprint(w, "</h1><p>")
   159      fmt.Fprintf(w, "\n\nError ID: %s\n", errID)
   160  
   161      if logger == nil {
   162          return
   163      }
   164  
   165      _, file, line, _ := runtime.Caller(1)
   166  
   167      logger.Printf("HTTP handler error ID %s at %s:%d: %v; message: %s\n", errID, file, line, err, responseMessage)
   168  }
   169  
   170  func writeErr(w http.ResponseWriter, status int, err error) {
   171      writeErrf(w, status, err, "")
   172  }
   173  {{end}}
   174  
   175  {{define "Handler"}}
   176  {{if .StoreImportPath}}
   177  import store "{{.StoreImportPath}}"
   178  {{end}}
   179  
   180  type {{$.Struct.LocalName}}Handler struct {
   181      Allower
   182      Store *store.{{$.Struct.LocalName}}Store
   183  }
   184  {{end}}
   185  
   186  {{define "HandlerMethods"}}
   187  import "net/http"
   188  import "encoding/json"
   189  {{if .StoreImportPath}}
   190  import store "{{.StoreImportPath}}"
   191  {{end}}
   192  
   193  
   194  func (h *{{$.Struct.LocalName}}Handler) GetByID(w http.ResponseWriter, r *http.Request) {
   195      {{$idf := index $.Struct.FieldList.PK 0}}
   196      var err error
   197      var in store.{{$.Struct.LocalName}}
   198      idParam := param(r, "id")
   199      err = scanParam(&in.{{$idf.GoName}}, idParam)
   200      if err != nil {
   201          writeErrf(w, 400, err, "invalid ID %q", idParam)
   202          return
   203      }
   204      id := in.{{$idf.GoName}}
   205      err = h.Allow(&in, Read)
   206      if err != nil {
   207          writeErrf(w, 403, err, "access not allowed to record with ID %v", id)
   208          return
   209      }
   210      ret, err := h.Store.SelectByID(r.Context(), id)
   211      if err != nil {
   212          writeErrf(w, 0, err, "failed to load record with ID %v", id)
   213          return
   214      }
   215      err = json.NewEncoder(w).Encode(ret)
   216      if err != nil {
   217          writeErrf(w, 0, err, "json encoding error")
   218          return
   219      }
   220  }
   221  
   222  /*
   223  func (h *XYZHandler) Post(w http.ResponseWriter, r *http.Request) {
   224  }
   225  
   226  func (h *XYZHandler) Patch(w http.ResponseWriter, r *http.Request) {
   227  }
   228  
   229  func (h *XYZHandler) Delete(w http.ResponseWriter, r *http.Request) {
   230  }
   231  
   232  func (h *XYZHandler) Select(w http.ResponseWriter, r *http.Request) {
   233  }
   234  
   235  func (h *XYZHandler) SelectCursor(w http.ResponseWriter, r *http.Request) {
   236  }
   237  */
   238  {{end}}
   239  
   240  {{define "TestHandler"}}
   241  {{end}}