Skip to content
This repository was archived by the owner on Oct 12, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Data Validator API
A Go library for validating Brazilian documents, and an HTTP service built on it.

```bash
go get github.com/jeferson0306/api-data-validator/validate
go get github.com/jeferson0306/brdoc/validate
```

```go
Expand Down Expand Up @@ -47,7 +47,7 @@ is wrong — see `validate/inscricao_estadual_test.go`.
## Command line

```bash
go install github.com/jeferson0306/api-data-validator/cmd/brdoc@latest
go install github.com/jeferson0306/brdoc/cmd/brdoc@latest

brdoc cpf 529.982.247-25 && echo accepted
brdoc ie 0100482300112 AC
Expand Down
2 changes: 1 addition & 1 deletion cmd/brdoc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"os"
"strings"

"github.com/jeferson0306/api-data-validator/validate"
"github.com/jeferson0306/brdoc/validate"
)

const (
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/jeferson0306/api-data-validator
module github.com/jeferson0306/brdoc

go 1.22.5

Expand Down
16 changes: 2 additions & 14 deletions handlers/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import (
"strings"
"time"

"github.com/jeferson0306/api-data-validator/internal/cache"
"github.com/jeferson0306/api-data-validator/models"
"github.com/jeferson0306/api-data-validator/validate"
"github.com/jeferson0306/brdoc/models"
"github.com/jeferson0306/brdoc/validate"

"github.com/google/uuid"
)
Expand Down Expand Up @@ -102,17 +101,6 @@ func validateItem(item models.BatchItem) models.BatchResult {
return result
}

// CPF is the one check routed through the cache, so that from_cache means
// the same thing on both endpoints.
if key == "cpf" {
outcome, fromCache := cache.CPF(item.Value)
result.Value = outcome.Normalized
result.IsValid = outcome.Valid
result.Message = outcome.Reason
result.FromCache = fromCache
return result
}

outcome, known := validate.ByKey(key, item.Value, item.Qualifier)
if !known {
// Distinguished from a failed validation on purpose: an unknown key is
Expand Down
2 changes: 1 addition & 1 deletion handlers/batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"
"testing"

"github.com/jeferson0306/api-data-validator/models"
"github.com/jeferson0306/brdoc/models"
)

func postBatch(t *testing.T, body string) (*httptest.ResponseRecorder, models.BatchResponse) {
Expand Down
29 changes: 5 additions & 24 deletions handlers/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,14 @@ package handlers
import (
"net/http"

"github.com/jeferson0306/api-data-validator/internal/cache"

"github.com/gin-gonic/gin"
)

// HealthHandler reports whether the service is up and whether its cache is
// reachable.
// HealthHandler reports that the service is up.
//
// The cache is reported but never gates the status: validation is pure
// computation and stays correct with Redis down, so a degraded cache must not
// take the service out of a load balancer. It exists to make the degradation
// visible — a silently unreachable Redis is how this service spent its first
// deployment paying latency for a cache that never returned a hit.
// There is nothing else to report. Validation is arithmetic with no
// dependencies: if the process is answering, it is working. A health check that
// enumerates subsystems the service does not have is theatre.
func HealthHandler(c *gin.Context) {
// A local named "cache" would shadow the package; more importantly, there
// are now three states rather than two. "disabled" is not a fault.
status := "disabled"
switch {
case !cache.Enabled():
case cache.Healthy():
status = "ok"
default:
status = "unreachable"
}

c.JSON(http.StatusOK, gin.H{
"status": "ok",
"cache": status,
})
c.JSON(http.StatusOK, gin.H{"status": "ok"})
}
23 changes: 5 additions & 18 deletions handlers/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package handlers

import (
"encoding/json"
"github.com/jeferson0306/api-data-validator/internal/cache"
"github.com/jeferson0306/api-data-validator/models"
"github.com/jeferson0306/api-data-validator/validate"
"github.com/jeferson0306/brdoc/models"
"github.com/jeferson0306/brdoc/validate"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -73,19 +72,8 @@ func ValidateHandler(w http.ResponseWriter, r *http.Request) {

// The qualifier is only read for the validations that take one; passing it
// unconditionally keeps this loop from growing a special case per document.
// CPF is the one check routed through the cache, because from_cache is part
// of the published response. Everything else goes straight to the library.
var (
result validate.Result
fromCache bool
)
if key == "cpf" {
result, fromCache = cache.CPF(value)
} else {
result, _ = validate.ByKey(key, value, r.URL.Query().Get("uf"))
}

response = createResponse(key, value, result.Normalized, result.Valid, result.Reason, start, fromCache)
result, _ := validate.ByKey(key, value, r.URL.Query().Get("uf"))
response = createResponse(key, value, result.Normalized, result.Valid, result.Reason, start)

writeResponse(w, response)
}
Expand Down Expand Up @@ -138,7 +126,7 @@ func writeResponse(w http.ResponseWriter, response models.ValidationResponse) {
}

// createResponse creates a response with the provided data.
func createResponse(key, rawValue, sanitizedValue string, isValid bool, message string, start time.Time, fromCache bool) models.ValidationResponse {
func createResponse(key, rawValue, sanitizedValue string, isValid bool, message string, start time.Time) models.ValidationResponse {
statusCode := http.StatusOK
errorCode := ""
if !isValid {
Expand All @@ -157,6 +145,5 @@ func createResponse(key, rawValue, sanitizedValue string, isValid bool, message
RequestID: uuid.New().String(),
Timestamp: time.Now(),
ExecutionTimeMs: int(time.Since(start).Milliseconds()),
FromCache: fromCache,
}
}
2 changes: 1 addition & 1 deletion handlers/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"net/http/httptest"
"testing"

"github.com/jeferson0306/api-data-validator/models"
"github.com/jeferson0306/brdoc/models"
)

func TestValidateHandlerMissingParameter(t *testing.T) {
Expand Down
109 changes: 0 additions & 109 deletions internal/cache/cache.go

This file was deleted.

31 changes: 20 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
"syscall"
"time"

"github.com/jeferson0306/api-data-validator/docs"
"github.com/jeferson0306/api-data-validator/handlers"
"github.com/jeferson0306/api-data-validator/middleware"
"github.com/jeferson0306/api-data-validator/observability"
"github.com/jeferson0306/brdoc/docs"
"github.com/jeferson0306/brdoc/handlers"
"github.com/jeferson0306/brdoc/middleware"
"github.com/jeferson0306/brdoc/observability"

"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
Expand All @@ -39,14 +39,23 @@ func main() {

configureClientAddressing(router, logger)

router.GET("/health", handlers.HealthHandler)
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
router.GET("/validate", func(c *gin.Context) {
handlers.ValidateHandler(c.Writer, c.Request)
})
router.POST("/validate/batch", func(c *gin.Context) {
handlers.BatchHandler(c.Writer, c.Request)
})

validate := func(c *gin.Context) { handlers.ValidateHandler(c.Writer, c.Request) }
batch := func(c *gin.Context) { handlers.BatchHandler(c.Writer, c.Request) }

// Versioned routes are where new work goes.
v1 := router.Group("/v1")
v1.GET("/health", handlers.HealthHandler)
v1.GET("/validate", validate)
v1.POST("/validate/batch", batch)

// 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.
router.GET("/health", handlers.HealthHandler)
router.GET("/validate", validate)
router.POST("/validate/batch", batch)

server := &http.Server{
Addr: ":" + port(),
Expand Down
2 changes: 0 additions & 2 deletions models/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ type ValidationResponse struct {
Timestamp time.Time `json:"timestamp"`
ExecutionTimeMs int `json:"execution_time_ms"`
LocationData map[string]interface{} `json:"location_data,omitempty"`
FromCache bool `json:"from_cache"`
}

// BatchRequest is one form's worth of values, checked in a single call.
Expand Down Expand Up @@ -66,5 +65,4 @@ type BatchResult struct {
Value string `json:"value"`
IsValid bool `json:"is_valid"`
Message string `json:"message"`
FromCache bool `json:"from_cache"`
}
2 changes: 1 addition & 1 deletion validate/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package validate_test
import (
"testing"

"github.com/jeferson0306/api-data-validator/validate"
"github.com/jeferson0306/brdoc/validate"
)

// These exist to answer one question the service's design depends on: is any of
Expand Down
2 changes: 1 addition & 1 deletion validate/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package validate_test
import (
"fmt"

"github.com/jeferson0306/api-data-validator/validate"
"github.com/jeferson0306/brdoc/validate"
)

func ExampleCPF() {
Expand Down
Loading