request/response: add interfaces and implementations
This commit is contained in:
parent
3b16d6b16a
commit
099d1aeb0f
@ -6,8 +6,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -24,6 +22,8 @@ type Context struct {
|
|||||||
// current handler index
|
// current handler index
|
||||||
index int
|
index int
|
||||||
|
|
||||||
|
params map[string]any
|
||||||
|
|
||||||
hasTimeout bool
|
hasTimeout bool
|
||||||
writerMux *sync.Mutex
|
writerMux *sync.Mutex
|
||||||
}
|
}
|
||||||
@ -123,128 +123,6 @@ func (ctx *Context) SetHandlers(handlers []ControllerHandler) {
|
|||||||
// }}}
|
// }}}
|
||||||
// {{{ Implements request functions
|
// {{{ Implements request functions
|
||||||
|
|
||||||
// {{{ Request URI
|
|
||||||
|
|
||||||
// QueryInt gets an int value from the query request
|
|
||||||
func (ctx *Context) QueryInt(key string, defval int) (int, error) {
|
|
||||||
params, err := ctx.QueryAll()
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
if vals, ok := params[key]; ok {
|
|
||||||
len := len(vals)
|
|
||||||
if len > 0 {
|
|
||||||
intval, err := strconv.Atoi(vals[len-1]) // return the last elem
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
return intval, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defval, errors.New("key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryString gets a string value from the query request
|
|
||||||
func (ctx *Context) QueryString(key string, defval string) (string, error) {
|
|
||||||
params, err := ctx.QueryAll()
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
if vals, ok := params[key]; ok {
|
|
||||||
len := len(vals)
|
|
||||||
if len > 0 {
|
|
||||||
return vals[len-1], nil // return the last elem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defval, errors.New("key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryArray gets an array of string values from the query request
|
|
||||||
func (ctx *Context) QueryArray(key string, defval []string) ([]string, error) {
|
|
||||||
params, err := ctx.QueryAll()
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
if vals, ok := params[key]; ok {
|
|
||||||
return vals, nil // return the last elem
|
|
||||||
}
|
|
||||||
return defval, errors.New("key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryAll returns all queries in a request URL
|
|
||||||
func (ctx *Context) QueryAll() (url.Values, error) {
|
|
||||||
if ctx.request != nil {
|
|
||||||
return map[string][]string(ctx.request.URL.Query()), nil
|
|
||||||
}
|
|
||||||
return url.Values{}, errors.New("missing request in the context")
|
|
||||||
}
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
// {{{ Post form
|
|
||||||
|
|
||||||
// FormInt gets an int value from the submitted form
|
|
||||||
func (ctx *Context) FormInt(key string, defval int) (int, error) {
|
|
||||||
vals, err := ctx.FormAll()
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
|
|
||||||
valStrs, ok := vals[key]
|
|
||||||
if !ok {
|
|
||||||
return defval, errors.New("key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
valInt, err := strconv.Atoi(valStrs[0]) // Get the first one as result
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return valInt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormString gets a string value from the submitted form
|
|
||||||
func (ctx *Context) FormString(key string, defval string) (string, error) {
|
|
||||||
vals, err := ctx.FormAll()
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
|
|
||||||
valStrs, ok := vals[key]
|
|
||||||
if !ok {
|
|
||||||
return defval, errors.New("key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return valStrs[0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormArray gets an array of string values from the submitted form
|
|
||||||
func (ctx *Context) FormArray(key string, defval []string) ([]string, error) {
|
|
||||||
vals, err := ctx.FormAll()
|
|
||||||
if err != nil {
|
|
||||||
return defval, err
|
|
||||||
}
|
|
||||||
|
|
||||||
valStrs, ok := vals[key]
|
|
||||||
if !ok {
|
|
||||||
return defval, errors.New("key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return valStrs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormAll gets everything from the submitted form
|
|
||||||
func (ctx *Context) FormAll() (url.Values, error) {
|
|
||||||
if ctx.request != nil {
|
|
||||||
err := ctx.request.ParseForm()
|
|
||||||
if err != nil {
|
|
||||||
return url.Values{}, err
|
|
||||||
}
|
|
||||||
return ctx.request.PostForm, err
|
|
||||||
}
|
|
||||||
return url.Values{}, errors.New("missing request in the context")
|
|
||||||
}
|
|
||||||
|
|
||||||
// }}}
|
|
||||||
// {{{ application/json
|
// {{{ application/json
|
||||||
|
|
||||||
// ReadJSON binds the request JSON body to an object.
|
// ReadJSON binds the request JSON body to an object.
|
||||||
|
283
framework/request.go
Normal file
283
framework/request.go
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
package framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
23
framework/response.go
Normal file
23
framework/response.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package framework
|
||||||
|
|
||||||
|
type IResponse interface {
|
||||||
|
WriteJSON(obj any) IResponse
|
||||||
|
WriteJSONP(obj any) IResponse
|
||||||
|
WriteXML(obj any) IResponse
|
||||||
|
WriteHTML(template string, obj any) IResponse
|
||||||
|
WriteText(format string, values ...any) IResponse
|
||||||
|
|
||||||
|
Redirect(path string) IResponse
|
||||||
|
SetHeader(key string, val string) IResponse
|
||||||
|
SetCookie(
|
||||||
|
key string,
|
||||||
|
val string,
|
||||||
|
maxAge int,
|
||||||
|
path, domain string,
|
||||||
|
secure, httpOnly bool,
|
||||||
|
) IResponse
|
||||||
|
SetStatus(code int) IResponse
|
||||||
|
|
||||||
|
// set 200
|
||||||
|
SetOkStatus() IResponse
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -1,3 +1,5 @@
|
|||||||
module git.vinchent.xyz/vinchent/go-web
|
module git.vinchent.xyz/vinchent/go-web
|
||||||
|
|
||||||
go 1.22.5
|
go 1.22.5
|
||||||
|
|
||||||
|
require github.com/spf13/cast v1.7.0
|
||||||
|
12
go.sum
12
go.sum
@ -0,0 +1,12 @@
|
|||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||||
|
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
Loading…
Reference in New Issue
Block a user