Documentation
¶
Index ¶
- Constants
- Variables
- func Bind(r *http.Request, v any, binders ...Binder) error
- func Chain(h http.Handler, mws ...Middleware) http.Handler
- func ClientIP(ctx context.Context) string
- func DelCookie(w http.ResponseWriter, name string, opts ...CookieOption)
- func Error(w http.ResponseWriter, r *http.Request, err error, opts ...ErrorOption)
- func GetAuthError(ctx context.Context) error
- func GetCookie(r *http.Request, name string) (string, error)
- func GetIdentity(ctx context.Context) any
- func NewClientIPMiddleware(trustedProxiesCIDR []string) func(http.Handler) http.Handler
- func NewHandler[Req any, Res any](fn HandlerFunc[Req, Res], opts ...Option) http.HandlerFunc
- func NewResponder[Req any, Res Responder](fn HandlerFunc[Req, Res], opts ...Option) http.HandlerFunc
- func NewStreamHandler[Req any, Res Streamable](fn HandlerFunc[Req, Res], opts ...Option) http.HandlerFunc
- func RegisterOnShutdown(ctx context.Context, fn func())
- func SetCookie(w http.ResponseWriter, name string, value string, opts ...CookieOption)
- func Validate(ctx context.Context, v any, validators ...*validator.Validate) error
- type AuthErrorKey
- type AuthStrategy
- func AuthChain(strategies ...AuthStrategy) AuthStrategy
- func FromCookie(name string, validator func(context.Context, string) (any, error)) AuthStrategy
- func FromHeader(scheme string, validator func(context.Context, string) (any, error)) AuthStrategy
- func FromQuery(param string, validator func(context.Context, string) (any, error)) AuthStrategy
- func WithAuthChallenge(strategy AuthStrategy, headerKey, headerVal string) AuthStrategy
- type Binder
- type BinderType
- type BizCoder
- type CORSOptions
- type ClientAuthBinder
- type CookieOption
- type ErrorCoder
- type ErrorFunc
- type ErrorOption
- type FileResponse
- type FormBinder
- type HandlerFunc
- type HttpError
- type IdentityKey
- type JsonBinder
- type Limiter
- type LogFunc
- type Middleware
- func Auth(strategy AuthStrategy, Errors ...ErrorFunc) Middleware
- func AuthRequired(challengeWith http.HandlerFunc) Middleware
- func CORS(opts CORSOptions) Middleware
- func DefaultCORS() Middleware
- func Logger(logFunc LogFunc) Middleware
- func RateLimit(limiter Limiter, Errors ...ErrorFunc) Middleware
- func Recovery(opts ...ErrorOption) Middleware
- func SecurityHeaders(cfgs ...SecurityConfig) Middleware
- type NoContent
- type Option
- func AddBinders(b ...Binder) Option
- func NoEnvelope() Option
- func WithBinders(b ...Binder) Option
- func WithErrorFunc(handler ErrorFunc) Option
- func WithErrorHook(hook func(ctx context.Context, err error)) Option
- func WithMaxBodySize(maxBytes int64) Option
- func WithMultipartLimit(limit int64) Option
- func WithValidator(v *validator.Validate) Option
- type PathBinder
- type PublicError
- type QueryBinder
- type RawBytes
- type Redirect
- type Responder
- type Response
- type Router
- func (r *Router) Group(pattern string, middleware ...func(http.Handler) http.Handler) *Router
- func (r *Router) Handle(pattern string, handler http.Handler)
- func (r *Router) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
- func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
- type SecurityConfig
- type SelfValidatable
- type ShutdownManager
- type Streamable
Constants ¶
const ( // CodeOK 表示成功 CodeOK = "OK" // CodeInternalError 服务器内部错误 (500) CodeInternalError = "INTERNAL_ERROR" // CodeBadRequest 请求参数错误 (400) CodeBadRequest = "BAD_REQUEST" CodeUnauthorized = "UNAUTHORIZED" // CodeForbidden 无权限 (403) CodeForbidden = "FORBIDDEN" // CodeNotFound 资源不存在 (404) CodeNotFound = "NOT_FOUND" // CodeTooManyRequests 请求过多 (429) CodeTooManyRequests = "TOO_MANY_REQUESTS" // CodeConflict 资源冲突 (409) CodeConflict = "CONFLICT" // CodeValidation 校验失败 (400) CodeValidation = "VALIDATION_FAILED" // CodeRequestEntityTooLarge 请求体过大 (413) CodeRequestEntityTooLarge = "REQUEST_ENTITY_TOO_LARGE" )
预定义业务错误码
const DefaultMultipartMemory = 8 << 20
DefaultMultipartMemory 8MB
Variables ¶
var ( ErrBadRequest = &HttpError{HttpCode: http.StatusBadRequest, BizCode: CodeBadRequest, Msg: "Bad Request"} ErrForbidden = &HttpError{HttpCode: http.StatusForbidden, BizCode: CodeForbidden, Msg: "Forbidden"} ErrNotFound = &HttpError{HttpCode: http.StatusNotFound, BizCode: CodeNotFound, Msg: "Not Found"} ErrTooManyRequests = &HttpError{HttpCode: http.StatusTooManyRequests, BizCode: CodeTooManyRequests, Msg: "Too Many Requests"} ErrInternal = &HttpError{HttpCode: http.StatusInternalServerError, BizCode: CodeInternalError, Msg: "Internal Server Error"} ErrRequestEntityTooLarge = &HttpError{HttpCode: http.StatusRequestEntityTooLarge, BizCode: CodeRequestEntityTooLarge, Msg: "Request Entity Too Large"} )
var Binders = []Binder{ &PathBinder{}, &QueryBinder{}, &JsonBinder{DisallowUnknownFields: true}, &FormBinder{MaxMemory: DefaultMultipartMemory}, }
Binders 默认绑定器链
var ErrNoCredentials = errors.New("no credentials found")
ErrNoCredentials 是一个特定的信号错误。 当策略返回此错误时,AuthChain 会忽略它并尝试下一个策略。
var ErrorHook func(ctx context.Context, err error) = nil
ErrorHook 是一个回调函数,用于处理错误的副作用(如记录日志)。 用户可以在 NewHandler 的 Option 中覆盖它。
var GetTraceID func(ctx context.Context) string = nil
GetTraceID 是一个依赖注入点。 外部库(如 o11y)应该设置这个函数,以便 httpx 能获取到 TraceID。
var SafeMode = true
SafeMode 控制是否开启错误脱敏。 建议在生产环境设置为 true。
var SchemaDecoder = func() *schema.Decoder { d := schema.NewDecoder() d.SetAliasTag("form") d.IgnoreUnknownKeys(true) return d }()
SchemaDecoder 用于 Query 和 Form 的解码 gorilla/schema 内部已有缓存机制,性能良好
var Validator = validator.New()
Validator 是默认的验证器实例
Functions ¶
func ClientIP ¶ added in v1.4.5
ClientIP retrieves the client IP from the context. It returns an empty string if the middleware was not applied.
func DelCookie ¶ added in v1.5.0
func DelCookie(w http.ResponseWriter, name string, opts ...CookieOption)
DelCookie 删除 Cookie。 为了防止残留,它会尝试删除该名字的所有可能变体(__Host-, __Secure-, 原名)。
func Error ¶
func Error(w http.ResponseWriter, r *http.Request, err error, opts ...ErrorOption)
Error 负责将 error 转换为 HTTP 响应并写入 ResponseWriter。
func GetAuthError ¶ added in v1.5.1
func GetCookie ¶ added in v1.5.0
GetCookie 透明地获取 Cookie 值。 它会按照安全优先级依次尝试:__Host-name -> __Secure-name -> name。 这意味着如果存在安全的变体,我们将优先读取它,忽略不安全的同名 Cookie(防御 Cookie Tossing)。
func NewClientIPMiddleware ¶ added in v1.4.5
NewClientIPMiddleware creates a middleware that extracts the real client IP. trustedProxiesCIDR is a list of CIDR strings (e.g., "10.0.0.0/8", "127.0.0.1/32"). If trustedProxiesCIDR is nil or empty, it defaults to trusting NO proxies (only RemoteAddr) for security, OR you can decide to trust all if you explicitly pass specific value (not implemented here for safety). NOTE: To trust all (e.g. dev mode), pass "0.0.0.0/0".
func NewHandler ¶
func NewHandler[Req any, Res any](fn HandlerFunc[Req, Res], opts ...Option) http.HandlerFunc
func NewResponder ¶ added in v1.4.7
func NewResponder[Req any, Res Responder](fn HandlerFunc[Req, Res], opts ...Option) http.HandlerFunc
NewResponder 创建一个允许业务逻辑直接控制响应过程的处理器。 适用于重定向、文件下载、自定义状态码等。
func NewStreamHandler ¶ added in v1.4.1
func NewStreamHandler[Req any, Res Streamable](fn HandlerFunc[Req, Res], opts ...Option) http.HandlerFunc
NewStreamHandler 创建一个流式处理函数。
func RegisterOnShutdown ¶ added in v1.4.0
RegisterOnShutdown 在当前请求的上下文中注册一个关闭回调。 当 ShutdownManager.Shutdown 被调用时,这些回调会被并发执行。 适用于 WebSocket、SSE 等需要发送协议级关闭信号(如 Close Frame)的场景。
func SetCookie ¶ added in v1.5.0
func SetCookie(w http.ResponseWriter, name string, value string, opts ...CookieOption)
SetCookie 写入 Cookie。 除非显式使用 WithInsecure() 或设置了 Domain,否则它会自动添加 __Host- 前缀。
Types ¶
type AuthErrorKey ¶ added in v1.5.1
type AuthErrorKey struct{}
type AuthStrategy ¶ added in v1.5.0
AuthStrategy 定义从请求中提取身份的原子策略。
func AuthChain ¶ added in v1.5.0
func AuthChain(strategies ...AuthStrategy) AuthStrategy
AuthChain 职责链模式:按顺序尝试多种认证策略。 逻辑: 1. 如果策略成功 -> 立即返回身份。 2. 如果策略返回 ErrNoCredentials -> 继续尝试下一个。 3. 如果策略返回其他错误(如 Token 过期/签名错误) -> 立即终止并报错(不进行降级)。 4. 如果所有策略都未命中 -> 返回 ErrNoCredentials。
func FromCookie ¶ added in v1.5.0
FromCookie 创建一个从 Cookie 提取凭证的策略。 它透明地使用 httpx.GetCookie,自动支持 __Host- 和 __Secure- 前缀防御。
func FromHeader ¶ added in v1.5.0
FromHeader 创建一个从 Header 提取凭证的策略。 scheme: 认证前缀,如 "Bearer", "Basic", "DPoP"。不区分大小写。
func WithAuthChallenge ¶ added in v1.5.0
func WithAuthChallenge(strategy AuthStrategy, headerKey, headerVal string) AuthStrategy
WithAuthChallenge 装饰器:为 ErrNoCredentials 错误附加 Challenge Header。 当策略链彻底失败(即客户端完全未提供凭证)时,此装饰器将错误转换为 带有 WWW-Authenticate 的 401 错误。
type BinderType ¶ added in v0.2.0
type BinderType int
const ( BinderMeta BinderType = iota // Query, Header, Path BinderBody // JSON, XML, Form (互斥) )
type BizCoder ¶ added in v0.2.0
type BizCoder interface {
BizStatus() string
}
BizCoder 定义了如何提取业务错误码 (String)。 任何实现了此接口的 error,httpx 都会使用其返回的字符串作为响应体中的 code 字段。
type CORSOptions ¶
type CORSOptions struct {
AllowedOrigins []string
AllowedMethods []string
AllowedHeaders []string
ExposedHeaders []string
AllowCredentials bool
MaxAge int
}
CORSOptions 定义 CORS 配置
type ClientAuthBinder ¶ added in v1.5.2
type ClientAuthBinder struct{}
ClientAuthBinder 处理 HTTP Basic Auth 专门用于 OIDC/OAuth2 场景,自动提取 client_id 和 client_secret
func (*ClientAuthBinder) Bind ¶ added in v1.5.2
func (b *ClientAuthBinder) Bind(r *http.Request, v any) error
func (*ClientAuthBinder) Match ¶ added in v1.5.2
func (b *ClientAuthBinder) Match(r *http.Request) bool
func (*ClientAuthBinder) Name ¶ added in v1.5.2
func (b *ClientAuthBinder) Name() string
func (*ClientAuthBinder) Type ¶ added in v1.5.2
func (b *ClientAuthBinder) Type() BinderType
type CookieOption ¶ added in v1.5.0
CookieOption用于配置 Cookie 的属性。
func WithCookieDomain ¶ added in v1.5.0
func WithCookieDomain(domain string) CookieOption
WithCookieDomain 设置域名。 注意:通常为了安全性,不设置域名(默认当前Host)是最好的,除非你需要子域共享。
func WithCookiePath ¶ added in v1.5.0
func WithCookiePath(path string) CookieOption
WithCookiePath 设置路径,默认为 "/"。
func WithCookieTTL ¶ added in v1.5.0
func WithCookieTTL(duration time.Duration) CookieOption
WithCookieTTL 设置存活时间。
func WithExposed ¶ added in v1.5.0
func WithExposed() CookieOption
WithExposed 允许 JS 读取(移除 HttpOnly)。 警告:仅用于非敏感数据(如 UI 主题设置、用户偏好),绝不可用于 Token。
func WithInsecure ¶ added in v1.5.0
func WithInsecure() CookieOption
WithInsecure 允许 HTTP 传输。 仅用于本地 localhost 开发调试。
func WithSameSiteNone ¶ added in v1.5.0
func WithSameSiteNone() CookieOption
WithSameSiteNone 允许跨站携带(必须配合 Secure)。 仅用于第三方嵌入场景(如 iframe 中的支付窗口),极不推荐用于主鉴权。
func WithSameSiteStrict ¶ added in v1.5.0
func WithSameSiteStrict() CookieOption
WithSameSiteStrict 启用最严格的防 CSRF 模式。 在此模式下,任何跨站跳转(甚至是点击链接)都不会携带 Cookie。 适用于高敏感操作(如修改密码)或 API 接口。
type ErrorCoder ¶
type ErrorCoder interface {
HTTPStatus() int
}
ErrorCoder 定义了如何提取 HTTP 状态码。 任何实现了此接口的 error,httpx 都会使用其返回的状态码,而不是默认的 500。
type ErrorFunc ¶ added in v1.5.3
type ErrorFunc func(w http.ResponseWriter, r *http.Request, err error, opts ...ErrorOption)
type ErrorOption ¶ added in v1.5.3
type ErrorOption func(*errorConfig)
ErrorOption 定义配置 Error 处理行为的函数签名
func WithHandler ¶ added in v1.5.3
func WithHandler(fn ErrorFunc) ErrorOption
WithHandler 注入实际错误处理函数
func WithHook ¶ added in v1.5.3
func WithHook(fn func(context.Context, error)) ErrorOption
WithHook 注入错误钩子
func WithNoEnvelope ¶ added in v1.5.3
func WithNoEnvelope() ErrorOption
WithNoEnvelope 禁止使用标准信封包裹 (用于 OIDC 或特殊协议)
func WithStatus ¶ added in v1.5.3
func WithStatus(code int) ErrorOption
WithStatus 强制指定 HTTP 状态码 (覆盖 error 本身的推断)
type FileResponse ¶
FileResponse 是一个实现了 Streamable 的文件响应辅助类。
func (*FileResponse) Headers ¶
func (f *FileResponse) Headers() map[string]string
type FormBinder ¶ added in v1.1.0
type FormBinder struct {
MaxMemory int64
}
FormBinder 处理 multipart/form-data 和 x-www-form-urlencoded
func (*FormBinder) Name ¶ added in v1.1.0
func (b *FormBinder) Name() string
func (*FormBinder) Type ¶ added in v1.1.0
func (b *FormBinder) Type() BinderType
type HandlerFunc ¶
HandlerFunc 定义业务处理函数签名。 坚持使用标准 context.Context,避免框架耦合, 我们和 gin 那样的框架有本质上的不同, 我们所有的实现都是通过配置和中间件完成, 所谓渐进式开发即是如此, 用户不必依赖我们, 但有我们会更好。
type HttpError ¶
HttpError 是一个通用的错误实现,同时满足 error, ErrorCoder 和 BizCoder 接口。 HttpError 被视为“安全的”,因为它是开发者显式构造的业务错误。
func NewError ¶ added in v0.2.0
NewError 创建一个新的 HttpError。 httpCode: HTTP 状态码 (如 404) bizCode: 业务错误码 (如 "USER_NOT_FOUND") msg: 错误描述
func (*HttpError) HTTPStatus ¶
func (*HttpError) PublicMessage ¶ added in v1.4.3
type IdentityKey ¶
type IdentityKey struct{}
type JsonBinder ¶ added in v1.1.0
type JsonBinder struct {
// DisallowUnknownFields 控制是否允许 JSON 中包含结构体未定义的字段。
// 默认为 true (不允许),否则可能导致“参数污染”或逻辑绕过。。
DisallowUnknownFields bool
}
JsonBinder 使用 sonic 进行极速解码
func (*JsonBinder) Name ¶ added in v1.1.0
func (b *JsonBinder) Name() string
func (*JsonBinder) Type ¶ added in v1.1.0
func (b *JsonBinder) Type() BinderType
type Middleware ¶
Middleware 标准中间件定义
func Auth ¶ added in v1.5.0
func Auth(strategy AuthStrategy, Errors ...ErrorFunc) Middleware
Auth 通用的认证中间件构造器。 它负责通用的“管道工作”:调用策略 -> 处理错误 -> 注入Context -> 继续执行。
func AuthRequired ¶ added in v1.5.0
func AuthRequired(challengeWith http.HandlerFunc) Middleware
AuthRequired 认证中间件,要求必须提供身份。
func DefaultCORS ¶
func DefaultCORS() Middleware
DefaultCORS 返回一个宽容的 CORS 中间件(开发环境常用)。 注意:为了安全,默认禁用了 AllowCredentials。 如果需要携带 Cookie/Auth 头,请手动配置 CORS 并指定具体的 AllowedOrigins。
func RateLimit ¶
func RateLimit(limiter Limiter, Errors ...ErrorFunc) Middleware
RateLimit 返回一个限流中间件。
func SecurityHeaders ¶ added in v1.4.0
func SecurityHeaders(cfgs ...SecurityConfig) Middleware
SecurityHeaders 返回一个中间件,用于添加通用的安全响应头。 包括: - X-Frame-Options: DENY (防止点击劫持) - X-Content-Type-Options: nosniff (防止 MIME 嗅探) - X-XSS-Protection: 1; mode=block (开启 XSS 过滤) - Referrer-Policy: strict-origin-when-cross-origin (控制 Referrer 泄露)
type NoContent ¶ added in v1.4.7
type NoContent struct {
Status int
}
NoContent 用于返回 204 等空响应
func (NoContent) WriteResponse ¶ added in v1.4.7
func (nc NoContent) WriteResponse(w http.ResponseWriter, r *http.Request)
type Option ¶
type Option func(*config)
func AddBinders ¶ added in v0.2.0
AddBinders 在默认 Binder 链之前添加自定义 Binder
func WithBinders ¶ added in v0.2.0
WithBinders 设置自定义的 Binder 链(将覆盖默认链)
func WithErrorFunc ¶ added in v1.5.3
WithErrorFunc 设置该 Handler 专属的错误处理器
func WithErrorHook ¶ added in v0.2.0
WithErrorHook 设置该 Handler 专属的错误处理 Hook
func WithMaxBodySize ¶ added in v1.1.0
WithMaxBodySize 限制请求体 (Body) 的最大字节数。 超过限制时将返回 413 Request Entity Too Large。 这是一个硬限制,会切断连接,有效防止大文件上传攻击或磁盘耗尽。 建议值:常规 API 设为 2MB-10MB;文件上传接口根据业务需求设定 (如 100MB)。
func WithMultipartLimit ¶ added in v1.1.0
WithMultipartLimit 设置解析 Multipart 表单时的最大内存限制 (字节)。 默认值为 8MB (DefaultMultipartMemory)。 设置此选项会创建一个新的 FormBinder 实例并替换掉默认链中的实例, 这样可以避免修改全局变量,也不破坏链中其他 Binder 的配置。
func WithValidator ¶ added in v0.2.0
WithValidator 设置自定义的 Validator 实例
type PathBinder ¶ added in v1.4.0
type PathBinder struct{}
PathBinder 处理 URL 路径参数 (Go 1.22+)
func (*PathBinder) Name ¶ added in v1.4.0
func (b *PathBinder) Name() string
func (*PathBinder) Type ¶ added in v1.4.0
func (b *PathBinder) Type() BinderType
type PublicError ¶ added in v1.4.3
type PublicError interface {
PublicMessage() string
}
PublicError 定义了该错误是否包含可安全展示给前端的信息。 在 SafeMode=true 时,只有实现了此接口且 PublicMessage() 返回非空,或者具体类型为 *HttpError 的错误, 其原本的 Error() 内容才会被返回给客户端,否则将被替换为 "Internal Server Error"。
type QueryBinder ¶ added in v1.1.0
type QueryBinder struct{}
QueryBinder 处理 URL 查询参数
func (*QueryBinder) Name ¶ added in v1.1.0
func (b *QueryBinder) Name() string
func (*QueryBinder) Type ¶ added in v1.1.0
func (b *QueryBinder) Type() BinderType
type RawBytes ¶ added in v1.4.7
RawBytes 直接写入原始字节流,带上自定义 Content-Type。
func (RawBytes) WriteResponse ¶ added in v1.4.7
func (rb RawBytes) WriteResponse(w http.ResponseWriter, r *http.Request)
type Redirect ¶ added in v1.4.7
Redirect 实现了 Responder 接口,用于重定向。
func (Redirect) WriteResponse ¶ added in v1.4.7
func (rd Redirect) WriteResponse(w http.ResponseWriter, r *http.Request)
type Responder ¶ added in v1.4.7
type Responder interface {
WriteResponse(w http.ResponseWriter, r *http.Request)
}
Responder 让业务返回值能够自主决定如何写入 ResponseWriter。 这是我们的“逃生舱”,用于处理重定向、静态文件或自定义 Header 等场景。
type Response ¶
type Response[T any] struct { // Code 是业务错误码 (字符串),例如 "OK", "INVALID_PARAM", "USER_BANNED"。 // 它与 HTTP Status Code 分离,由前端用于展示具体的错误文案。 Code string `json:"code"` Message string `json:"message"` Data T `json:"data,omitempty"` TraceID string `json:"trace_id,omitempty"` }
Response 是默认的统一响应信封。
type Router ¶ added in v1.4.5
type Router struct {
// contains filtered or unexported fields
}
Router wraps http.ServeMux to provide grouping and middleware capabilities.
func (*Router) Group ¶ added in v1.4.5
Group creates a sub-router mounted at the specified pattern configuration. The pattern should be a path prefix like "/api/v1". Accessing the sub-router via the pattern will strip the pattern prefix.
func (*Router) Handle ¶ added in v1.4.5
Handle registers the handler for the given pattern. It applies the router's middleware chain to the handler.
func (*Router) HandleFunc ¶ added in v1.4.5
HandleFunc registers the handler function for the given pattern.
type SecurityConfig ¶ added in v1.4.3
type SecurityConfig struct {
// HSTSMaxAgeSeconds 启用 Strict-Transport-Security。0 表示禁用。
// 生产环境建议设置为 31536000 (1年)。
HSTSMaxAgeSeconds int
// HSTSIncludeSubdomains 是否包含子域名
HSTSIncludeSubdomains bool
// CSP Content-Security-Policy 值。
// 例如: "default-src 'self'"
CSP string
}
SecurityConfig 定义安全头配置
type SelfValidatable ¶
SelfValidatable 是高性能验证接口。 如果 Request 结构体实现了此接口,将跳过反射验证。
type ShutdownManager ¶ added in v1.4.0
type ShutdownManager struct {
// contains filtered or unexported fields
}
ShutdownManager 管理活跃连接的优雅关闭
func NewShutdownManager ¶ added in v1.4.0
func NewShutdownManager() *ShutdownManager
NewShutdownManager 创建一个新的关闭管理器
func (*ShutdownManager) Middleware ¶ added in v1.4.0
func (m *ShutdownManager) Middleware(next http.Handler) http.Handler
Middleware 返回一个中间件,用于跟踪请求生命周期并注入关闭支持。
Source Files
¶
- binder.go
- binder_client.go
- binder_form.go
- binder_json.go
- binder_path.go
- binder_query.go
- cookie.go
- error.go
- error_func.go
- httpx.go
- middleware.go
- middleware_auth.go
- middleware_clientip.go
- middleware_cors.go
- middleware_ratelimit.go
- middleware_security.go
- options.go
- responder.go
- response.go
- router.go
- shutdown.go
- validator.go