|
@@ -0,0 +1,236 @@
|
|
|
+package wisp
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "encoding/json"
|
|
|
+ "encoding/xml"
|
|
|
+ "errors"
|
|
|
+ "io"
|
|
|
+ "net/http"
|
|
|
+ "net/url"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "github.com/julienschmidt/httprouter"
|
|
|
+)
|
|
|
+
|
|
|
+type Context struct {
|
|
|
+ response http.ResponseWriter
|
|
|
+ request *http.Request
|
|
|
+ params httprouter.Params
|
|
|
+ ctx context.Context
|
|
|
+}
|
|
|
+
|
|
|
+// Basic getters
|
|
|
+
|
|
|
+func (c *Context) Response() http.ResponseWriter {
|
|
|
+ return c.response
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Request() *http.Request {
|
|
|
+ return c.request
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Params() httprouter.Params {
|
|
|
+ return c.params
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Context() context.Context {
|
|
|
+ return c.ctx
|
|
|
+}
|
|
|
+
|
|
|
+// URL Param retrieval (from path)
|
|
|
+
|
|
|
+func (c *Context) Param(name string) string {
|
|
|
+ return c.params.ByName(name)
|
|
|
+}
|
|
|
+
|
|
|
+// Query param retrieval
|
|
|
+
|
|
|
+func (c *Context) Query(name string) string {
|
|
|
+ return c.request.URL.Query().Get(name)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) QueryDefault(name, defaultValue string) string {
|
|
|
+ if v := c.Query(name); v != "" {
|
|
|
+ return v
|
|
|
+ }
|
|
|
+ return defaultValue
|
|
|
+}
|
|
|
+
|
|
|
+// Form param retrieval (POST, PUT with form data)
|
|
|
+
|
|
|
+func (c *Context) FormValue(name string) string {
|
|
|
+ return c.request.FormValue(name)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) FormValueDefault(name, defaultValue string) string {
|
|
|
+ if v := c.FormValue(name); v != "" {
|
|
|
+ return v
|
|
|
+ }
|
|
|
+ return defaultValue
|
|
|
+}
|
|
|
+
|
|
|
+// Body binding helpers
|
|
|
+
|
|
|
+func (c *Context) BindJSON(dest interface{}) error {
|
|
|
+ defer c.request.Body.Close()
|
|
|
+ dec := json.NewDecoder(c.request.Body)
|
|
|
+ dec.DisallowUnknownFields()
|
|
|
+ return dec.Decode(dest)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) BindXML(dest interface{}) error {
|
|
|
+ defer c.request.Body.Close()
|
|
|
+ dec := xml.NewDecoder(c.request.Body)
|
|
|
+ return dec.Decode(dest)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) BindForm() (url.Values, error) {
|
|
|
+ defer c.request.Body.Close()
|
|
|
+ contentType := c.request.Header.Get("Content-Type")
|
|
|
+ if !strings.Contains(contentType, "application/x-www-form-urlencoded") {
|
|
|
+ return nil, errors.New("content-type is not application/x-www-form-urlencoded")
|
|
|
+ }
|
|
|
+ return url.ParseQuery(c.request.PostForm.Encode())
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) BindMultipartForm(maxMemory int64) error {
|
|
|
+ return c.request.ParseMultipartForm(maxMemory)
|
|
|
+}
|
|
|
+
|
|
|
+// Cookie helpers
|
|
|
+
|
|
|
+func (c *Context) Cookie(name string) (*http.Cookie, error) {
|
|
|
+ return c.request.Cookie(name)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) SetCookie(cookie *http.Cookie) {
|
|
|
+ http.SetCookie(c.response, cookie)
|
|
|
+}
|
|
|
+
|
|
|
+// Response helpers
|
|
|
+
|
|
|
+func (c *Context) Write(data []byte) (int, error) {
|
|
|
+ return c.response.Write(data)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) String(status int, s string) error {
|
|
|
+ _, err := io.WriteString(c.response, s)
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) JSON(status int, data any) error {
|
|
|
+ c.response.Header().Set("Content-Type", "application/json")
|
|
|
+ c.response.WriteHeader(status)
|
|
|
+ return json.NewEncoder(c.response).Encode(data)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) XML(status int, data any) error {
|
|
|
+ c.response.Header().Set("Content-Type", "application/xml")
|
|
|
+ c.response.WriteHeader(status)
|
|
|
+ return xml.NewEncoder(c.response).Encode(data)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Redirect(status int, urlStr string) {
|
|
|
+ http.Redirect(c.response, c.request, urlStr, status)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Status(code int) {
|
|
|
+ c.response.WriteHeader(code)
|
|
|
+}
|
|
|
+
|
|
|
+// Helpers for common status responses
|
|
|
+
|
|
|
+func (c *Context) NoContent() {
|
|
|
+ c.Status(http.StatusNoContent)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) NotFound() {
|
|
|
+ c.Status(http.StatusNotFound)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) BadRequest(e error) error {
|
|
|
+ c.response.WriteHeader(http.StatusBadRequest)
|
|
|
+ _, err := c.response.Write([]byte(e.Error()))
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) InternalServerError(e error) error {
|
|
|
+ c.response.WriteHeader(http.StatusInternalServerError)
|
|
|
+ _, err := c.response.Write([]byte(e.Error()))
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+// Context cancellation / deadline
|
|
|
+
|
|
|
+func (c *Context) Done() <-chan struct{} {
|
|
|
+ return c.ctx.Done()
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Err() error {
|
|
|
+ return c.ctx.Err()
|
|
|
+}
|
|
|
+
|
|
|
+// Request parsing helpers for common data types
|
|
|
+
|
|
|
+func (c *Context) ParamInt(name string) (int, error) {
|
|
|
+ v := c.Param(name)
|
|
|
+ return strconv.Atoi(v)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) ParamIntDefault(name string, defaultValue int) int {
|
|
|
+ v := c.Param(name)
|
|
|
+ if v == "" {
|
|
|
+ return defaultValue
|
|
|
+ }
|
|
|
+ i, err := strconv.Atoi(v)
|
|
|
+ if err != nil {
|
|
|
+ return defaultValue
|
|
|
+ }
|
|
|
+ return i
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) QueryInt(name string) (int, error) {
|
|
|
+ v := c.Query(name)
|
|
|
+ return strconv.Atoi(v)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) QueryIntDefault(name string, defaultValue int) int {
|
|
|
+ v := c.Query(name)
|
|
|
+ if v == "" {
|
|
|
+ return defaultValue
|
|
|
+ }
|
|
|
+ i, err := strconv.Atoi(v)
|
|
|
+ if err != nil {
|
|
|
+ return defaultValue
|
|
|
+ }
|
|
|
+ return i
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) FormInt(name string) (int, error) {
|
|
|
+ v := c.FormValue(name)
|
|
|
+ return strconv.Atoi(v)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) FormIntDefault(name string, defaultValue int) int {
|
|
|
+ v := c.FormValue(name)
|
|
|
+ if v == "" {
|
|
|
+ return defaultValue
|
|
|
+ }
|
|
|
+ i, err := strconv.Atoi(v)
|
|
|
+ if err != nil {
|
|
|
+ return defaultValue
|
|
|
+ }
|
|
|
+ return i
|
|
|
+}
|
|
|
+
|
|
|
+// Context management helpers
|
|
|
+
|
|
|
+func (c *Context) SetValue(key, val any) {
|
|
|
+ c.ctx = context.WithValue(c.ctx, key, val)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *Context) Value(key any) any {
|
|
|
+ return c.ctx.Value(key)
|
|
|
+}
|