Skip to content

Commit b8026a4

Browse files
committed
feat!: extend netip.Addr support to ipv6
1 parent 4fd3cdb commit b8026a4

File tree

6 files changed

+31
-3
lines changed

6 files changed

+31
-3
lines changed

docs/docs/features/request-inputs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ The following special types are supported out of the box:
102102
| `time.Time` | `{"type": "string", "format": "date-time"}` | `"2020-01-01T12:00:00Z"` |
103103
| `url.URL` | `{"type": "string", "format": "uri"}` | `"https://example.com"` |
104104
| `net.IP` | `{"type": "string", "format": "ipv4"}` | `"127.0.0.1"` |
105-
| `netip.Addr` | `{"type": "string", "format": "ipv4"}` | `"127.0.0.1"` |
105+
| `netip.Addr` | `{"type": "string", "format": "ip"}` | `"127.0.0.1"` or `fe80::1` |
106106
| `json.RawMessage` | `{}` | `["whatever", "you", "want"]` |
107107

108108
You can override this default behavior if needed as described in [Schema Customization](./schema-customization.md) and [Request Validation](./request-validation.md), e.g. setting a custom `format` tag for IPv6.

schema.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ func schemaFromType(r Registry, t reflect.Type) *Schema {
722722
case ipType:
723723
return &Schema{Type: TypeString, Nullable: isPointer, Format: "ipv4"}
724724
case ipAddrType:
725-
return &Schema{Type: TypeString, Nullable: isPointer, Format: "ipv4"}
725+
return &Schema{Type: TypeString, Nullable: isPointer, Format: "ip"}
726726
case rawMessageType:
727727
return &Schema{}
728728
}

schema_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func TestSchema(t *testing.T) {
190190
{
191191
name: "ipAddr",
192192
input: netip.AddrFrom4([4]byte{127, 0, 0, 1}),
193-
expected: `{"type": "string", "format": "ipv4"}`,
193+
expected: `{"type": "string", "format": "ip"}`,
194194
},
195195
{
196196
name: "json.RawMessage",

validate.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"math"
77
"net"
88
"net/mail"
9+
"net/netip"
910
"net/url"
1011
"reflect"
1112
"regexp"
@@ -247,6 +248,10 @@ func validateFormat(path *PathBuffer, str string, s *Schema, res *ValidateResult
247248
if ip := net.ParseIP(str); ip == nil || ip.To16() == nil {
248249
res.Add(path, str, validation.MsgExpectedRFC2373IPv6)
249250
}
251+
case "ip":
252+
if _, err := netip.ParseAddr(str); err != nil {
253+
res.Add(path, str, validation.MsgExpectedRFCIPAddr)
254+
}
250255
case "uri", "uri-reference", "iri", "iri-reference":
251256
if _, err := url.Parse(str); err != nil {
252257
res.Add(path, str, ErrorFormatter(validation.MsgExpectedRFC3986URI, err))

validate_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,28 @@ var validateTests = []struct {
433433
input: map[string]any{"value": "1234"},
434434
errs: []string{"expected string to be RFC 2373 ipv6"},
435435
},
436+
{
437+
name: "ipv4 success",
438+
typ: reflect.TypeOf(struct {
439+
Value string `json:"value" format:"ip"`
440+
}{}),
441+
input: map[string]any{"value": "127.0.0.1"},
442+
},
443+
{
444+
name: "ipv6 success",
445+
typ: reflect.TypeOf(struct {
446+
Value string `json:"value" format:"ip"`
447+
}{}),
448+
input: map[string]any{"value": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"},
449+
},
450+
{
451+
name: "expected ipv4 or ipv6",
452+
typ: reflect.TypeOf(struct {
453+
Value string `json:"value" format:"ip"`
454+
}{}),
455+
input: map[string]any{"value": "1234"},
456+
errs: []string{"expected string to be either RFC 2673 ipv4 or RFC 2373 ipv6"},
457+
},
436458
{
437459
name: "uri success",
438460
typ: reflect.TypeOf(struct {

validation/messages.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var (
1111
MsgExpectedRFC5890Hostname = "expected string to be RFC 5890 hostname"
1212
MsgExpectedRFC2673IPv4 = "expected string to be RFC 2673 ipv4"
1313
MsgExpectedRFC2373IPv6 = "expected string to be RFC 2373 ipv6"
14+
MsgExpectedRFCIPAddr = "expected string to be either RFC 2673 ipv4 or RFC 2373 ipv6"
1415
MsgExpectedRFC3986URI = "expected string to be RFC 3986 uri: %v"
1516
MsgExpectedRFC4122UUID = "expected string to be RFC 4122 uuid: %v"
1617
MsgExpectedRFC6570URITemplate = "expected string to be RFC 6570 uri-template"

0 commit comments

Comments
 (0)