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) }