go-web/framework/request.go

412 lines
8.9 KiB
Go
Raw Normal View History

package framework
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"io"
"mime/multipart"
"net/url"
"github.com/spf13/cast"
)
type IRequest interface {
// url query
// e.g. foo.com?a=1&b=bar&c[]=bar
QueryAll(key string) url.Values
QueryInt(key string, defval int) (int, bool)
QueryInt64(key string, defval int64) (int64, bool)
QueryFloat32(key string, defval float32) (float32, bool)
QueryFloat64(key string, defval float64) (float64, bool)
QueryBool(key string, defval bool) (bool, bool)
QueryString(key string, defval string) (string, bool)
QueryStringSlice(key string, defval []string) ([]string, bool)
// url params
// e.g. /book/:id
Param(key string) any
ParamInt(key string, defval int) (int, bool)
ParamInt64(key string, defval int64) (int64, bool)
ParamFloat32(key string, defval float32) (float32, bool)
ParamFloat64(key string, defval float64) (float64, bool)
ParamBool(key string, defval bool) (bool, bool)
ParamString(key string, defval string) (string, bool)
// form
FormAll(key string) url.Values
FormInt(key string, defval int) (int, bool)
FormInt64(key string, defval int64) (int64, bool)
FormFloat32(key string, defval float32) (float32, bool)
FormFloat64(key string, defval float64) (float64, bool)
FormBool(key string, defval bool) (bool, bool)
FormString(key string, defval string) (string, bool)
FormStringSlice(key string, defval []string) ([]string, bool)
FormFile(key string) (*multipart.FileHeader, error)
// JSON body
BindJSON(obj any) error
// XML body
BindXML(obj any) error
// RAW body
GetRawData() ([]byte, error)
// Basic informations
Uri() string
Method() string
Host() string
ClientIP() string
// Header
Headers() map[string][]string
Header(key string) (string, bool)
// Cookie
Cookies() map[string]string
Cookie(key string) (string, bool)
}
// {{{ url query
// QueryAll returns all queries in a request URL
func (ctx *Context) QueryAll() url.Values {
if ctx.request != nil {
return map[string][]string(ctx.request.URL.Query())
}
return url.Values{}
}
// QueryInt gets an int value from the query request
func (ctx *Context) QueryInt(key string, defval int) (int, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryInt64(key string, defval int64) (int64, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt64(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryBool(key string, defval bool) (bool, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToBool(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryFloat32(key string, defval float32) (float32, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat32(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) QueryFloat64(key string, defval float64) (float64, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat64(vals[0]), true
}
}
return defval, false
}
// QueryString gets a string value from the query request
func (ctx *Context) QueryString(key string, defval string) (string, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToString(vals[0]), true
}
}
return defval, false
}
// QueryArray gets an array of string values from the query request
func (ctx *Context) QueryStringSlice(key string, defval []string) ([]string, bool) {
params := ctx.QueryAll()
if vals, ok := params[key]; ok {
return cast.ToStringSlice(vals[0]), true
}
return defval, false
}
// }}}
// {{{ url params
func (ctx *Context) Param(key string) any {
if ctx.params != nil {
if val, ok := ctx.params[key]; ok {
return val
}
}
return nil
}
func (ctx *Context) ParamInt(key string, def int) (int, bool) {
if val := ctx.Param(key); val != nil {
return cast.ToInt(val), true
}
return def, false
}
func (ctx *Context) ParamInt64(key string, def int64) (int64, bool) {
if val := ctx.Param(key); val != nil {
return cast.ToInt64(val), true
}
return def, false
}
func (ctx *Context) ParamFloat64(key string, def float64) (float64, bool) {
if val := ctx.Param(key); val != nil {
return cast.ToFloat64(val), true
}
return def, false
}
func (ctx *Context) ParamFloat32(key string, def float32) (float32, bool) {
if val := ctx.Param(key); val != nil {
return cast.ToFloat32(val), true
}
return def, false
}
func (ctx *Context) ParamBool(key string, def bool) (bool, bool) {
if val := ctx.Param(key); val != nil {
return cast.ToBool(val), true
}
return def, false
}
func (ctx *Context) ParamString(key string, def string) (string, bool) {
if val := ctx.Param(key); val != nil {
return cast.ToString(val), true
}
return def, false
}
// }}}
// {{{ Post form
// FormAll gets everything from the submitted form
func (ctx *Context) FormAll() url.Values {
if ctx.request != nil {
_ = ctx.request.ParseForm()
return ctx.request.PostForm
}
return url.Values{}
}
// FormInt gets an int value from the submitted form
func (ctx *Context) FormInt(key string, defval int) (int, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormInt64(key string, defval int64) (int64, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToInt64(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormBool(key string, defval bool) (bool, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToBool(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormFloat32(key string, defval float32) (float32, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat32(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormFloat64(key string, defval float64) (float64, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToFloat64(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormString(key string, defval string) (string, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
if len(vals) > 0 {
return cast.ToString(vals[0]), true
}
}
return defval, false
}
func (ctx *Context) FormStringSlice(key string, defval []string) ([]string, bool) {
params := ctx.FormAll()
if vals, ok := params[key]; ok {
return cast.ToStringSlice(vals[0]), true
}
return defval, false
}
// }}}
// {{{ type binder
var (
ErrNoRequest = errors.New("missing request in the context")
ErrNotSingleObj = errors.New("body must have only a single value")
)
// JSON body
func (ctx *Context) BindJSON(obj any) error {
if ctx.request == nil {
return ErrNoRequest
}
dec := json.NewDecoder(ctx.request.Body)
err := dec.Decode(obj)
if err != nil {
return err
}
err = dec.Decode(&struct{}{})
if err != io.EOF {
return ErrNotSingleObj
}
return nil
}
// XML body
func (ctx *Context) BindXML(obj any) error {
if ctx.request == nil {
return ErrNoRequest
}
dec := xml.NewDecoder(ctx.request.Body)
err := dec.Decode(obj)
if err != nil {
return err
}
err = dec.Decode(&struct{}{})
if err != io.EOF {
return ErrNotSingleObj
}
return nil
}
// RAW body
func (ctx *Context) GetRawData() ([]byte, error) {
if ctx.request == nil {
return []byte{}, ErrNoRequest
}
body, err := io.ReadAll(ctx.request.Body)
if err != nil {
return []byte{}, err
}
/* Restore the body (io.ReadCloser) to it's original state */
ctx.request.Body = io.NopCloser(bytes.NewBuffer(body))
return body, nil
}
// }}}
// {{{ Basic informations
func (ctx *Context) Uri() string {
return ctx.request.RequestURI
}
func (ctx *Context) Method() string {
return ctx.request.Method
}
func (ctx *Context) Host() string {
return ctx.request.Host
}
func (ctx *Context) ClientIP() string {
r := ctx.request
ipAddress := r.Header.Get("X-Real-Ip")
if ipAddress == "" {
ipAddress = r.Header.Get("X-Forwarded-For")
}
if ipAddress == "" {
ipAddress = r.RemoteAddr
}
return ipAddress
}
// }}}
// {{{ Headers
// Header
func (ctx *Context) Headers() map[string][]string {
return ctx.request.Header
}
func (ctx *Context) Header(key string) (string, bool) {
vals := ctx.request.Header.Values(key)
if vals == nil || len(vals) <= 0 {
return "", false
}
return vals[0], true
}
// }}}
// {{{ Cookies
// Cookies gets cookie key-value pairs
func (ctx *Context) Cookies() map[string]string {
cookies := ctx.request.Cookies()
ret := map[string]string{}
for _, c := range cookies {
ret[c.Name] = c.Value
}
return ret
}
func (ctx *Context) Cookie(key string) (string, bool) {
cookies := ctx.Cookies()
if val, ok := cookies[key]; ok {
return val, true
}
return "", false
}
// }}}