diff --git a/framework/context.go b/framework/context.go index c702404..8bd882b 100644 --- a/framework/context.go +++ b/framework/context.go @@ -2,9 +2,6 @@ package framework import ( "context" - "encoding/json" - "errors" - "io" "net/http" "sync" "time" @@ -121,49 +118,3 @@ func (ctx *Context) SetHandlers(handlers []ControllerHandler) { } // }}} -// {{{ Implements request functions - -// {{{ application/json - -// ReadJSON binds the request JSON body to an object. -// -// A pointer of obj should be passed. -func (ctx *Context) ReadJSON(obj any) error { - if ctx.request == nil { - return errors.New("missing request in the context") - } - dec := json.NewDecoder(ctx.request.Body) - err := dec.Decode(obj) - if err != nil { - return err - } - err = dec.Decode(&struct{}{}) - if err != io.EOF { - return errors.New("body must have only a single JSON value") - } - - return nil -} - -// WriteJSON send back an object in JSON format with the status code -func (ctx *Context) WriteJSON(status int, obj any) error { - // There is a timeout, some error message data must have already been - // written to the output. Stop writing anything into the responseWriter. - if ctx.HasTimeout() { - return nil - } - data, err := json.Marshal(obj) - if err != nil { - return err - } - ctx.responseWriter.Header().Set("Content-type", "application/json") - ctx.responseWriter.WriteHeader(status) - _, err = ctx.responseWriter.Write(data) - if err != nil { - return err - } - return nil -} - -// }}} -// }}} diff --git a/framework/response.go b/framework/response.go index 31c5fac..8dd00ce 100644 --- a/framework/response.go +++ b/framework/response.go @@ -1,10 +1,18 @@ package framework +import ( + "encoding/json" + "encoding/xml" + "fmt" + "html/template" + "net/http" + "net/url" +) + type IResponse interface { - WriteJSON(obj any) IResponse - WriteJSONP(obj any) IResponse - WriteXML(obj any) IResponse - WriteHTML(template string, obj any) IResponse + WriteJSON(status int, obj any) IResponse + WriteXML(status int, obj any) IResponse + WriteHTML(status int, filepath string, obj any) IResponse WriteText(format string, values ...any) IResponse Redirect(path string) IResponse @@ -21,3 +29,95 @@ type IResponse interface { // set 200 SetOkStatus() IResponse } + +func (ctx *Context) WriteJSON(status int, obj any) IResponse { + // There is a timeout, some error message data must have already been + // written to the output. Stop writing anything into the responseWriter. + if ctx.HasTimeout() { + return nil + } + data, err := json.Marshal(obj) + if err != nil { + return ctx.SetStatus(http.StatusInternalServerError) + } + ctx.responseWriter.Header().Set("Content-type", "application/json") + ctx.responseWriter.WriteHeader(status) + _, _ = ctx.responseWriter.Write(data) + return ctx +} + +func (ctx *Context) WriteXML(status int, obj any) IResponse { + // There is a timeout, some error message data must have already been + // written to the output. Stop writing anything into the responseWriter. + if ctx.HasTimeout() { + return nil + } + data, err := xml.Marshal(obj) + if err != nil { + return ctx.SetStatus(http.StatusInternalServerError) + } + ctx.responseWriter.Header().Set("Content-type", "application/json") + ctx.responseWriter.WriteHeader(status) + _, _ = ctx.responseWriter.Write(data) + return ctx +} + +func (ctx *Context) WriteHTML(status int, filepath string, obj any) IResponse { + ctx.SetHeader("Content-Type", "application/html") + t, _ := template.New("output").ParseFiles(filepath) + t.Execute(ctx.responseWriter, obj) + + return ctx +} + +func (ctx *Context) WriteText(format string, values ...any) IResponse { + out := fmt.Sprintf(format, values...) + ctx.SetHeader("Content-Type", "application/text") + ctx.responseWriter.Write([]byte(out)) + return ctx +} + +func (ctx *Context) Redirect(path string) IResponse { + http.Redirect(ctx.responseWriter, ctx.request, path, http.StatusTemporaryRedirect) + return ctx +} + +func (ctx *Context) SetHeader(key string, val string) IResponse { + ctx.responseWriter.Header().Add(key, val) + return ctx +} + +func (ctx *Context) SetCookie( + key string, + val string, + maxAge int, + path, domain string, + secure, httpOnly bool, +) IResponse { + if path == "" { + path = "/" + } + + http.SetCookie(ctx.responseWriter, &http.Cookie{ + Name: key, + Value: url.QueryEscape(val), + MaxAge: maxAge, + Path: path, + Domain: domain, + SameSite: http.SameSiteDefaultMode, + Secure: secure, + HttpOnly: httpOnly, + }) + return ctx +} + +func (ctx *Context) SetStatus(code int) IResponse { + ctx.responseWriter.WriteHeader(code) + return ctx +} + +// set 200 +func (ctx *Context) SetOkStatus() IResponse { + ctx.responseWriter.WriteHeader(http.StatusOK) + return ctx +}