Skip to content

Conversation

@rshelekhov
Copy link
Contributor

@rshelekhov rshelekhov commented Oct 28, 2025

Description

Added IPv4() validator for string schema to validate IPv4 address format.

Motivation

IPv4 validation is a common requirement for:

  • Network configuration inputs
  • API endpoints dealing with IP addresses
  • Form validations for server IPs, DNS settings, etc.

This validator is present in similar libraries (Zod, go-playground/validator)
and would be a valuable addition to Zog.

Implementation Details

  • Uses Go's standard net.ParseIP() function
  • Validates with To4() method to ensure IPv4 format (not IPv6)
  • Handles edge cases: empty strings, invalid formats, IPv6 addresses

Changes

  • Added IPv4() method to StringSchema in string.go
  • Added ErrCodeIPv4 constant in zconst/zconst.go
  • Added default error message in i18n/en/en.go
  • Added comprehensive tests in string_validate_test.go
  • Added parse tests in string_test.go
  • Updated documentation in docs/reference.md

Testing

  • Added test cases for valid IPv4 addresses (192.168.1.1, 127.0.0.1)
  • Added test cases for invalid inputs (malformed IPs, out-of-range values, type coercion)
  • Added test cases for required field validation

Example Usage

schema := z.String().IPv4()

// Valid
schema.Validate("192.168.1.1")
schema.Validate("10.0.0.1")

// Invalid  
schema.Validate("256.1.1.1")    // octet too large
schema.Validate("192.168.1")    // incomplete
schema.Validate("2001:db8::1")  // IPv6

Closes issue #191

Summary by CodeRabbit

  • New Features

    • Added IPv4 string validation with a dedicated error code for invalid IPv4 addresses.
  • Documentation

    • Reference docs updated to describe the new IPv4 validation.
  • Localization

    • English and Spanish translations added for the IPv4 validation message.
  • Tests

    • New unit tests covering valid and invalid IPv4 inputs, optional vs required behavior, and type/coercion error cases.

- Added IPv4() method to StringSchema in string.go
- Added ErrCodeIPv4 constant in zconst/zconst.go
- Added default error message in i18n/en/en.go
- Added comprehensive tests in string_validate_test.go and string_test.go
- Updated documentation in docs/reference.md

The validator uses net.ParseIP() and To4() to ensure the address
is a valid IPv4 format and not IPv6.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Walkthrough

Added a String IPv4 validator: new StringSchema.IPv4() method (uses net.ParseIP(...).To4()), two zconst symbols (IssueCodeIP, IPv4), English/Spanish i18n entries, a docs line for z.String().IPv4(), and tests (including a duplicated test in string_test.go).

Changes

Cohort / File(s) Summary
Core implementation
string.go
Added net import and func (s *StringSchema[T]) IPv4(options ...TestOption) *StringSchema[T] which builds a test using net.ParseIP(...).To4() and registers it with issue code ip and parameter IPv4.
Error code constants
zconst/consts.go
Added constants: IssueCodeIP ZogIssueCode = "ip" and IPv4 = "IPv4" to the existing const block.
Internationalization
i18n/en/en.go, i18n/es/es.go
Added zconst.IssueCodeIP translations under TypeString (EN: "must be a valid {{ip}} address"; ES: "debe ser una dirección {{ip}} válida").
Documentation
docs/docs/reference.md
Added a documentation line for z.String().IPv4() under String primitive validations.
Tests
string_test.go, string_validate_test.go
Added TestStringIPv4 (appears duplicated in string_test.go) and TestStringValidateIPv4 covering valid IPv4s, invalid inputs, IPv6/mapped forms, empty/required behavior, and coercion error cases.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Caller as Validator caller
  participant Schema as StringSchema.IPv4
  participant Net as net.ParseIP/To4

  Caller->>Schema: Validate(value)
  Schema->>Net: ParseIP(value)
  Net-->>Schema: IP or nil
  alt IP != nil and To4() != nil
    Schema-->>Caller: success (no issue)
  else not IPv4
    Schema-->>Caller: return issue (IssueCodeIP, param "IPv4")
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check string.go IPv4 logic for correct nil/To4 checks and that rejection of IPv6/mapped addresses matches intent (including any colon check).
  • Verify naming/placement of IssueCodeIP and IPv4 constants and corresponding i18n keys.
  • Remove or justify duplicated TestStringIPv4 in string_test.go.
  • Confirm docs line accurately reflects the public API and error message parameter {{ip}}.

Possibly related issues

Poem

🐇
I hopped through bytes beneath the moonlight's hum,
Counting octets, one by one they come.
192.168.1.1 — a hop, a cheer, a smile,
No colons, pure four-fold steps across the tile.
✨🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat: add IPv4 validator for strings" is directly and fully related to the main change in the pull request. The changeset's core objective is to add an IPv4() validation method to the StringSchema type, and the title accurately captures this primary change. The title is concise, uses conventional commit formatting (feat:), and avoids vague or generic terms. A teammate scanning the repository history would immediately understand that this PR introduces IPv4 validation functionality for string schemas.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22aafa9 and f470728.

📒 Files selected for processing (1)
  • string_validate_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • string_validate_test.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
zconst/consts.go (1)

137-138: Constant definition is correct.

The IPv4 issue code follows the established naming pattern and is positioned logically after the URL constant.

Consider removing the extra blank line at Line 138 for consistency with other constant declarations in this block.

 	IssueCodeIPv4 ZogIssueCode = "ipv4"
-
string_test.go (1)

201-221: Good test coverage for basic IPv4 validation.

The tests cover valid addresses, invalid formats, out-of-range octets, and coercion behavior.

Consider adding the following test cases for more comprehensive coverage:

  1. IPv6 rejection test: Verify that IPv6 addresses like "2001:db8::1" or "::1" are properly rejected
  2. Negation test: Add test for String().Not().IPv4() for consistency with Email and URL validators (see TestStringNot lines 408-427 for examples)

Example additions:

// Add to TestStringIPv4
errs = field.Parse("2001:db8::1", &dest)
assert.NotEmpty(t, errs)
tutils.VerifyDefaultIssueMessages(t, errs)

errs = field.Parse("::1", &dest)
assert.NotEmpty(t, errs)
tutils.VerifyDefaultIssueMessages(t, errs)
// Add to TestStringNot around line 458
"not ipv4": {
	schema:         String().Not().IPv4(),
	strVal:         "not-an-ip",
	expectedErrMap: nil,
},
"not ipv4 failure": {
	schema: String().Not().IPv4(),
	strVal: "192.168.1.1",
	expectedErrMap: internals.ZogIssueList{
		&internals.ZogIssue{
			Code:    "not_ipv4",
			Dtype:   "string",
			Value:   tutils.PtrOf("192.168.1.1"),
			Message: "must not be a valid IPv4 address",
			Err:     nil,
		},
	},
},
string_validate_test.go (1)

210-245: Comprehensive validation test coverage.

The test covers valid IPv4 addresses, invalid formats, optional/required field behavior, and correct error code reporting.

Consider adding an IPv6 rejection test case to explicitly verify that IPv6 addresses are not accepted:

 	// Invalid cases
 	dest = "256.1.1.1"
 	errs = field.Validate(&dest)
 	assert.NotEmpty(t, errs)
 	assert.Equal(t, zconst.IssueCodeIPv4, errs[0].Code)
 
 	dest = "not-an-ip"
 	errs = field.Validate(&dest)
 	assert.NotEmpty(t, errs)
 	assert.Equal(t, zconst.IssueCodeIPv4, errs[0].Code)
+
+	// IPv6 should be rejected
+	dest = "2001:db8::1"
+	errs = field.Validate(&dest)
+	assert.NotEmpty(t, errs)
+	assert.Equal(t, zconst.IssueCodeIPv4, errs[0].Code)
 
 	// Required field with empty string

Also consider adding a negation test case in TestValidateStringNot (similar to the recommendation for string_test.go).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74abfd2 and cfe6ad9.

📒 Files selected for processing (6)
  • docs/docs/reference.md (1 hunks)
  • i18n/en/en.go (1 hunks)
  • string.go (2 hunks)
  • string_test.go (1 hunks)
  • string_validate_test.go (1 hunks)
  • zconst/consts.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
string_test.go (2)
string.go (1)
  • String (83-91)
tutils/testIssueMessages.go (1)
  • VerifyDefaultIssueMessages (14-32)
i18n/en/en.go (1)
zconst/consts.go (1)
  • IssueCodeIPv4 (137-137)
string_validate_test.go (3)
string.go (1)
  • String (83-91)
zconst/consts.go (2)
  • IssueCodeIPv4 (137-137)
  • IssueCodeRequired (63-63)
internals/tests.go (1)
  • Required (114-121)
string.go (5)
internals/tests.go (2)
  • TestOption (17-17)
  • Test (64-75)
utilsOptions.go (2)
  • TestOption (10-10)
  • IssueCode (32-36)
utils.go (2)
  • Test (42-42)
  • Ctx (12-12)
zconst/consts.go (1)
  • IssueCodeIPv4 (137-137)
internals/contexts.go (1)
  • Ctx (10-44)
🔇 Additional comments (3)
docs/docs/reference.md (1)

111-111: Documentation looks good.

The IPv4 validator is properly documented and positioned logically between URL and UUID validators.

i18n/en/en.go (1)

31-31: Translation entry looks good.

The error message is clear and consistent with other validators (Email, URL, UUID).

string.go (1)

4-4: Import addition is correct.

The net package is the appropriate standard library choice for IP validation.

Copy link
Owner

@Oudwins Oudwins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Thank you so much for this! As it sometimes happens AI got confused here.

I don't think there is a use case for wanting this validator in the not schema. At least from briefly thinking about it doesn't really seem useful. Happy to keep it in if you can think of a use case that wouldn't be better served with a different validator. Otherwise, I would prefer we remove it.

But other than that it looks great!

Copy link
Contributor Author

@rshelekhov rshelekhov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! Adjusted as suggested.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c9448e and 90ff4f9.

📒 Files selected for processing (1)
  • string.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
string.go (5)
internals/tests.go (2)
  • TestOption (17-17)
  • Test (64-75)
utilsOptions.go (2)
  • TestOption (10-10)
  • IssueCode (32-36)
utils.go (2)
  • Test (42-42)
  • Ctx (12-12)
zconst/consts.go (1)
  • IssueCodeIPv4 (137-137)
internals/contexts.go (1)
  • Ctx (10-44)
🔇 Additional comments (1)
string.go (1)

4-4: LGTM! Import is necessary for IPv4 validation.

The net package import is correctly added to support the new IPv4() validator method.

Copy link
Owner

@Oudwins Oudwins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @rshelekhov thank you for making the changes.

I must apologize because I said it looked good. But went on a walk thought a little bit more about it and I think to future proof the validation errors a bit more it would make sense to do a minor change on how the errors are generated. Hopefully its not too much trouble. Let me know if the explanations are not clear enough!

@rshelekhov rshelekhov requested a review from Oudwins November 1, 2025 20:29
Copy link
Owner

@Oudwins Oudwins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! With this changes and considerations I feel pretty confident that this is the right path forward. Left a few comments in the older threads beyond this I think we are good. Once this merges I will immediately do a release so if you are wanting to use this you can get access immediately.

Again apologies for all the back and forth

@rshelekhov
Copy link
Contributor Author

Hey! With this changes and considerations I feel pretty confident that this is the right path forward. Left a few comments in the older threads beyond this I think we are good. Once this merges I will immediately do a release so if you are wanting to use this you can get access immediately.

Again apologies for all the back and forth

No worries at all! I completely understand and really value your thorough approach. It’s definitely better to fine-tune the implementation now to make sure it’s done right. I just pushed the changes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 90ff4f9 and a9be589.

📒 Files selected for processing (5)
  • i18n/en/en.go (1 hunks)
  • i18n/es/es.go (1 hunks)
  • string.go (2 hunks)
  • string_validate_test.go (1 hunks)
  • zconst/consts.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • string_validate_test.go
🧰 Additional context used
🧬 Code graph analysis (3)
i18n/en/en.go (1)
zconst/consts.go (1)
  • IssueCodeIP (137-137)
string.go (5)
zconst/consts.go (2)
  • IPv4 (140-140)
  • IssueCodeIP (137-137)
internals/tests.go (2)
  • TestOption (17-17)
  • Test (64-75)
utilsOptions.go (3)
  • TestOption (10-10)
  • IssueCode (32-36)
  • Params (57-61)
utils.go (2)
  • Test (42-42)
  • Ctx (12-12)
internals/contexts.go (1)
  • Ctx (10-44)
i18n/es/es.go (1)
zconst/consts.go (1)
  • IssueCodeIP (137-137)

Copy link
Owner

@Oudwins Oudwins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Thank you so much. This looks great! I'll merge and release now!

@Oudwins Oudwins merged commit 3a64936 into Oudwins:master Nov 2, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants