You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

95 lines
2.5 KiB

package http
import (
"bytes"
"fmt"
"git.diulo.com/mogfee/kit/encoding"
"git.diulo.com/mogfee/kit/errors"
"git.diulo.com/mogfee/kit/internal/httputil"
"git.diulo.com/mogfee/kit/transport/http/binding"
"github.com/gorilla/mux"
"io"
"net/http"
"net/url"
)
const SupportPackageIsVersion1 = true
type Redirector interface {
Redirect() (string, int)
}
type Request = http.Request
type ResponseWriter = http.ResponseWriter
type Flusher = http.Flusher
type DecodeRequestFunc func(*http.Request, any) error
type EncodeResponseFunc func(http.ResponseWriter, *http.Request, any) error
type EncodeErrorFunc func(w http.ResponseWriter, r *http.Request, err error)
func DefaultRequestVars(r *http.Request, v any) error {
raws := mux.Vars(r)
vars := make(url.Values, len(raws))
for k, v := range raws {
vars[k] = []string{v}
}
return binding.BindQuery(vars, v)
}
func DefaultRequestQuery(r *http.Request, v any) error {
return binding.BindQuery(r.URL.Query(), v)
}
func DefaultRequestDecoder(r *http.Request, v any) error {
codec, ok := CodeForRequest(r, "Content-type")
if !ok {
return errors.BadRequest("CODEC", fmt.Sprintf("unregister Content-Type: %s", codec))
}
data, err := io.ReadAll(r.Body)
if err != nil {
return errors.BadRequest("CODEC", err.Error())
}
r.Body = io.NopCloser(bytes.NewBuffer(data))
if len(data) == 0 {
return nil
}
if err = codec.Unmarshal(data, v); err != nil {
return errors.BadRequest("CODEC", err.Error())
}
return nil
}
func DefaultResponseEncoder(w http.ResponseWriter, r *http.Request, v any) error {
if v == nil {
return nil
}
if rd, ok := v.(Redirector); ok {
url, code := rd.Redirect()
http.Redirect(w, r, url, code)
return nil
}
codec, _ := CodeForRequest(r, "Accept")
data, err := codec.Marshal(v)
if err != nil {
return err
}
w.Header().Set("Content-type", httputil.ContentType(codec.Name()))
_, err = w.Write(data)
return err
}
func DefaultErrorEncoder(w http.ResponseWriter, r *http.Request, err error) {
se := errors.FromError(err)
codec, _ := CodeForRequest(r, "Accept")
body, err := codec.Marshal(se)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", httputil.ContentType(codec.Name()))
w.WriteHeader(int(se.Status))
_, _ = w.Write(body)
}
func CodeForRequest(r *http.Request, name string) (encoding.Codec, bool) {
for _, accept := range r.Header[name] {
codec := encoding.GetCodec(httputil.ContentSubtype(accept))
if codec != nil {
return codec, true
}
}
return encoding.GetCodec("json"), false
}