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
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.Code)) |
|
_, _ = 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 |
|
}
|
|
|