This repository was archived by the owner on Oct 12, 2026. It is now read-only.
Repository navigation
refactor: make the validators an importable Go library - #10
Merged
Merged
Conversation
The logic was trapped inside an HTTP service. Nobody could go get it, the
module path was not even a valid import path, and importing the package would
have opened a Redis connection.
go get github.com/jeferson0306/api-data-validator/validate
result := validate.CPF("529.982.247-25")
result.Valid // true
result.Normalized // "52998224725"
The library is pure. No network, no cache, no configuration, no state, nothing
read from the environment. Validation is arithmetic, and arithmetic that needs
a server is arithmetic you cannot trust when the server is down.
Changes that make it one:
The module path is now importable, and the package is named for what it
provides rather than for where it happened to live. validate.CPF reads better
than utils.ValidateCPF, and Go style avoids the stutter.
Functions return a Result rather than three unnamed values. (bool, string,
string) is fine inside a package and hostile across one.
The Redis client left the library for internal/cache. It was a package-level
variable, so importing a CPF validator dialled a database.
The cache is now opt-in through REDIS_ADDR and off by default, which is also a
production fix: with no Redis configured the service was attempting a
connection and timing out on every CPF. /health gained a third state to say so.
Benchmarks were added, and they change the argument about the cache. A CPF
check runs in 522ns against a Redis round trip measured at 150-220ms in
production — five orders of magnitude apart. Building the cache key requires
normalising, and normalising is most of the validation, so the answer is
already computed before the cache is consulted. from_cache is kept because it
is published, but the numbers argue for removing both.
cmd/brdoc is a command line tool over the same library, exiting 0 for valid and
1 for invalid so it composes with a shell.
Seven runnable examples serve as documentation on pkg.go.dev and as tests.
main.go stays at the repository root so the existing deployment is untouched.
Smoke tested end to end: every endpoint answers, and the log still contains no
trace of the value being validated.
This was referenced Sep 4, 2026
jeferson0306
added a commit
that referenced
this pull request
Sep 4, 2026
Three changes that belong together because each is a break, and one break is cheaper than three. The module is github.com/jeferson0306/brdoc. api-data-validator described a service; what this mostly is now is a library, and .../api-data-validator/validate reads badly in an import block. GitHub redirects the old URL, and nothing depends on the old module path yet — which is precisely why this is the moment. The cache is gone. #10's benchmarks put a CPF check at 522ns against a Redis round trip measured at 150-220ms in production, and building the cache key required the normalised value, which is most of the validation — the answer was already computed before the cache was consulted. It was never an optimisation. from_cache leaves the response with it, and /health stops reporting a subsystem that no longer exists: validation is arithmetic with no dependencies, so if the process answers, it works. Enumerating subsystems a service does not have is theatre. /v1 is mounted, and the unversioned paths stay permanently. They were published, things point at them, and breaking a URL to tidy a prefix is a cost paid by other people. /v1 exists so the next change has somewhere to go rather than to move anyone today. Smoke tested against a running binary: both route generations answer, from_cache is absent from the response, and health reports one field.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The logic was trapped inside an HTTP service. Nobody could
go getit, the module path (DataValidatorAPI) was not even a valid import path, and importing the package would have opened a Redis connection.What makes it a library
The library is pure. No network, no cache, no configuration, no state, nothing read from the environment. Validation is arithmetic, and arithmetic that needs a server is arithmetic you cannot trust when the server is down.
The Redis client left the library for
internal/cache. It was a package-level variable, so importing a CPF validator dialled a database — the single clearest sign this was not a library.Functions return a
Resultrather than three unnamed values.(bool, string, string)is fine inside a package and hostile across one.The package is named for what it provides.
validate.CPFreads better thanutils.ValidateCPF, and Go style avoids the stutter.The benchmarks change an argument
A CPF check costs 522 nanoseconds. The Redis round trip measured in production was 150–220 milliseconds — five orders of magnitude apart. Worse, building the cache key requires the normalised value, and normalising is most of the validation, so the answer is already computed before the cache is consulted.
The cache is retained because
from_cacheis part of the published response, but the numbers argue for removing both. Your call — I did not want to drop a published field without asking.This is also a production fix. The cache is now opt-in through
REDIS_ADDR. With none configured — the current state on Render — the service was attempting a connection and timing out on every CPF request. It now skips it./healthgained a third state to say so:{"cache":"disabled","status":"ok"}Command line
Exit 0 for valid, 1 for invalid, 2 for usage — so it composes with a shell rather than needing to be parsed.
Documentation
Seven runnable examples, which are both the documentation on pkg.go.dev and tests that fail if the behaviour drifts. They cover the things worth knowing before using it: that stray characters are rejected rather than stripped, that a rejected value comes back untouched, and that
ieneeds its state.The deployment is untouched
main.gostays at the repository root, so the existing Render build command still finds it. Smoke tested end to end against a running binary: every endpoint answers correctly, the batch works, and the log still contains no trace of the value being validated.Follow-ups
The repository is named
api-data-validator, which makes the import path read oddly for a library. Renaming it — GitHub redirects the old URL — would givegithub.com/jeferson0306/brdoc/validate. Worth doing before anyone depends on the current path, but it is a decision, not a cleanup.