mirror of
https://github.com/slimtoolkit/slim.git
synced 2025-06-03 04:00:23 +00:00
![dependabot[bot]](/assets/img/avatar_default.png)
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.76.0 to 0.131.0. - [Release notes](https://github.com/getkin/kin-openapi/releases) - [Commits](https://github.com/getkin/kin-openapi/compare/v0.76.0...v0.131.0) --- updated-dependencies: - dependency-name: github.com/getkin/kin-openapi dependency-version: 0.131.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
172 lines
6.1 KiB
Go
172 lines
6.1 KiB
Go
package openapi3
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"net/netip"
|
|
"regexp"
|
|
)
|
|
|
|
type (
|
|
// FormatValidator is an interface for custom format validators.
|
|
FormatValidator[T any] interface {
|
|
Validate(value T) error
|
|
}
|
|
// StringFormatValidator is a type alias for FormatValidator[string]
|
|
StringFormatValidator = FormatValidator[string]
|
|
// NumberFormatValidator is a type alias for FormatValidator[float64]
|
|
NumberFormatValidator = FormatValidator[float64]
|
|
// IntegerFormatValidator is a type alias for FormatValidator[int64]
|
|
IntegerFormatValidator = FormatValidator[int64]
|
|
)
|
|
|
|
var (
|
|
// SchemaStringFormats is a map of custom string format validators.
|
|
SchemaStringFormats = make(map[string]StringFormatValidator)
|
|
// SchemaNumberFormats is a map of custom number format validators.
|
|
SchemaNumberFormats = make(map[string]NumberFormatValidator)
|
|
// SchemaIntegerFormats is a map of custom integer format validators.
|
|
SchemaIntegerFormats = make(map[string]IntegerFormatValidator)
|
|
)
|
|
|
|
const (
|
|
// FormatOfStringForUUIDOfRFC4122 is an optional predefined format for UUID v1-v5 as specified by RFC4122
|
|
FormatOfStringForUUIDOfRFC4122 = `^(?:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$`
|
|
|
|
// FormatOfStringForEmail pattern catches only some suspiciously wrong-looking email addresses.
|
|
// Use DefineStringFormat(...) if you need something stricter.
|
|
FormatOfStringForEmail = `^[^@]+@[^@<>",\s]+$`
|
|
|
|
// FormatOfStringByte is a regexp for base64-encoded characters, for example, "U3dhZ2dlciByb2Nrcw=="
|
|
FormatOfStringByte = `(^$|^[a-zA-Z0-9+/\-_]*=*$)`
|
|
|
|
// FormatOfStringDate is a RFC3339 date format regexp, for example "2017-07-21".
|
|
FormatOfStringDate = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])$`
|
|
|
|
// FormatOfStringDateTime is a RFC3339 date-time format regexp, for example "2017-07-21T17:32:28Z".
|
|
FormatOfStringDateTime = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`
|
|
)
|
|
|
|
func init() {
|
|
DefineStringFormatValidator("byte", NewRegexpFormatValidator(FormatOfStringByte))
|
|
DefineStringFormatValidator("date", NewRegexpFormatValidator(FormatOfStringDate))
|
|
DefineStringFormatValidator("date-time", NewRegexpFormatValidator(FormatOfStringDateTime))
|
|
DefineIntegerFormatValidator("int32", NewRangeFormatValidator(int64(math.MinInt32), int64(math.MaxInt32)))
|
|
DefineIntegerFormatValidator("int64", NewRangeFormatValidator(int64(math.MinInt64), int64(math.MaxInt64)))
|
|
}
|
|
|
|
// DefineIPv4Format opts in ipv4 format validation on top of OAS 3 spec
|
|
func DefineIPv4Format() {
|
|
DefineStringFormatValidator("ipv4", NewIPValidator(true))
|
|
}
|
|
|
|
// DefineIPv6Format opts in ipv6 format validation on top of OAS 3 spec
|
|
func DefineIPv6Format() {
|
|
DefineStringFormatValidator("ipv6", NewIPValidator(false))
|
|
}
|
|
|
|
type stringRegexpFormatValidator struct {
|
|
re *regexp.Regexp
|
|
}
|
|
|
|
func (s stringRegexpFormatValidator) Validate(value string) error {
|
|
if !s.re.MatchString(value) {
|
|
return fmt.Errorf(`string doesn't match pattern "%s"`, s.re.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type callbackValidator[T any] struct {
|
|
fn func(T) error
|
|
}
|
|
|
|
func (c callbackValidator[T]) Validate(value T) error {
|
|
return c.fn(value)
|
|
}
|
|
|
|
type rangeFormat[T int64 | float64] struct {
|
|
min, max T
|
|
}
|
|
|
|
func (r rangeFormat[T]) Validate(value T) error {
|
|
if value < r.min || value > r.max {
|
|
return fmt.Errorf("value should be between %v and %v", r.min, r.max)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewRangeFormatValidator creates a new FormatValidator that validates the value is within a given range.
|
|
func NewRangeFormatValidator[T int64 | float64](min, max T) FormatValidator[T] {
|
|
return rangeFormat[T]{min: min, max: max}
|
|
}
|
|
|
|
// NewRegexpFormatValidator creates a new FormatValidator that uses a regular expression to validate the value.
|
|
func NewRegexpFormatValidator(pattern string) StringFormatValidator {
|
|
re, err := regexp.Compile(pattern)
|
|
if err != nil {
|
|
err := fmt.Errorf("string regexp format has invalid pattern %q: %w", pattern, err)
|
|
panic(err)
|
|
}
|
|
return stringRegexpFormatValidator{re: re}
|
|
}
|
|
|
|
// NewCallbackValidator creates a new FormatValidator that uses a callback function to validate the value.
|
|
func NewCallbackValidator[T any](fn func(T) error) FormatValidator[T] {
|
|
return callbackValidator[T]{fn: fn}
|
|
}
|
|
|
|
// DefineStringFormatValidator defines a custom format validator for a given string format.
|
|
func DefineStringFormatValidator(name string, validator StringFormatValidator) {
|
|
SchemaStringFormats[name] = validator
|
|
}
|
|
|
|
// DefineNumberFormatValidator defines a custom format validator for a given number format.
|
|
func DefineNumberFormatValidator(name string, validator NumberFormatValidator) {
|
|
SchemaNumberFormats[name] = validator
|
|
}
|
|
|
|
// DefineIntegerFormatValidator defines a custom format validator for a given integer format.
|
|
func DefineIntegerFormatValidator(name string, validator IntegerFormatValidator) {
|
|
SchemaIntegerFormats[name] = validator
|
|
}
|
|
|
|
// DefineStringFormat defines a regexp pattern for a given string format
|
|
//
|
|
// Deprecated: Use openapi3.DefineStringFormatValidator(name, NewRegexpFormatValidator(pattern)) instead.
|
|
func DefineStringFormat(name string, pattern string) {
|
|
DefineStringFormatValidator(name, NewRegexpFormatValidator(pattern))
|
|
}
|
|
|
|
// DefineStringFormatCallback defines a callback function for a given string format
|
|
//
|
|
// Deprecated: Use openapi3.DefineStringFormatValidator(name, NewCallbackValidator(fn)) instead.
|
|
func DefineStringFormatCallback(name string, callback func(string) error) {
|
|
DefineStringFormatValidator(name, NewCallbackValidator(callback))
|
|
}
|
|
|
|
// NewIPValidator creates a new FormatValidator that validates the value is an IP address.
|
|
func NewIPValidator(isIPv4 bool) FormatValidator[string] {
|
|
return callbackValidator[string]{fn: func(ip string) error {
|
|
addr, err := netip.ParseAddr(ip)
|
|
if err != nil {
|
|
return &SchemaError{
|
|
Value: ip,
|
|
Reason: "Not an IP address",
|
|
}
|
|
}
|
|
if isIPv4 && !addr.Is4() {
|
|
return &SchemaError{
|
|
Value: ip,
|
|
Reason: "Not an IPv4 address (it's IPv6)",
|
|
}
|
|
}
|
|
if !isIPv4 && !addr.Is6() {
|
|
return &SchemaError{
|
|
Value: ip,
|
|
Reason: "Not an IPv6 address (it's IPv4)",
|
|
}
|
|
}
|
|
return nil
|
|
}}
|
|
}
|