request/response: add implementations for response writer

This commit is contained in:
Muyao CHEN 2024-09-26 09:32:44 +02:00
parent 8f4b378fdd
commit cb1ea9f701
2 changed files with 104 additions and 53 deletions

View File

@ -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
}
// }}}
// }}}

View File

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