
pedantigo v2: check request bodies in Echo and Gin
pedantigo v2 is the second major version of the MIT-licensed Go validation library. It keeps the validation engine, changes the default struct tag from pedantigo to validate, and adds plugins. The first plugins are binders for the Echo and Gin web frameworks.
What changed in v2
The table compares version 1 and version 2 of the library, area by area.
| Area | v1 | v2 |
|---|---|---|
| Module path | github.com/SmrutAI/pedantigo | github.com/SmrutAI/pedantigo/v2 |
| Import | github.com/SmrutAI/pedantigo | github.com/SmrutAI/pedantigo/v2/validator |
| Default tag | pedantigo | validate |
| Options type | ValidatorOptions | Options, with new TagName and MaxRecursionDepth fields |
| Web frameworks | None | Echo and Gin plugins, each its own Go module |
All the code lives in the validator package. Install it with:
go get github.com/SmrutAI/pedantigo/v2/validatorVersion 1 stays frozen at v1.1.4.
Why the default tag changed
The validate tag matches go-playground/validator and swaggo/swag. Structs written for that ecosystem now work with pedantigo without edits.
Migrate from v1
- Update the import to
github.com/SmrutAI/pedantigo/v2/validator. - Replace the
pedantigo.qualifier in your code withvalidator.. - Rename the struct tags to
validate, or callvalidator.SetTagName("pedantigo")before you create any validator. - Audit your tags in both directions.
Step 4 matters because the failure is silent. Version 2 ignores a leftover pedantigo:"..." tag, so the field becomes unconstrained, and no error appears. An existing validate:"..." tag that pedantigo never read before is now enforced.
Do not rename the literal word pedantigo in tags with a blind find and replace. Rename the ValidatorOptions type to Options by hand.
Register a type once
The plugins need to find your validator by type. Register each request type once.
type CreateUser struct {
Name string `json:"name" validate:"required,min=1,max=100"`
Email string `json:"email" validate:"required,email"`
}
var _ = validator.Register(validator.New[CreateUser]())A second Register call for the same type panics. New alone does not make the type findable.
Echo plugin
The Echo plugin is the module github.com/SmrutAI/pedantigo/plugins/web/pedantigoecho/v2. It provides a binder that replaces Echo's default.
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/SmrutAI/pedantigo/plugins/web/pedantigoecho/v2"
"github.com/SmrutAI/pedantigo/v2/validator"
)
type CreateUser struct {
Name string `json:"name" validate:"required,min=1,max=100"`
Email string `json:"email" validate:"required,email"`
}
var _ = validator.Register(validator.New[CreateUser]())
func create(c echo.Context) error {
var req CreateUser
if err := c.Bind(&req); err != nil {
return err // *echo.HTTPError, status 400
}
return c.JSON(http.StatusCreated, req)
}
func main() {
e := echo.New()
e.Binder = pedantigoecho.NewBinder()
e.POST("/users", create)
e.Logger.Fatal(e.Start(":8080"))
}The binder works in four steps:
- It binds path parameters first.
- For GET, DELETE and HEAD, it uses Echo's default binder for query parameters. pedantigo does not run.
- For POST, PUT and PATCH, it reads the body and validates it. A failure returns an
*echo.HTTPErrorwith status 400. - An empty body returns without validation.
A body with no email, or with "email":"not-an-email", returns the 400 error. A type that you did not register panics.
Gin plugin
The Gin plugin is the module github.com/SmrutAI/pedantigo/plugins/web/pedantigogin/v2. It installs two global hooks, a JSON codec and a validator, when you call NewBinder.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/SmrutAI/pedantigo/plugins/web/pedantigogin/v2"
"github.com/SmrutAI/pedantigo/v2/validator"
)
type CreateUser struct {
Name string `json:"name" binding:"required,min=1,max=100"`
Email string `json:"email" binding:"required,email"`
}
var _ = validator.Register(validator.New[CreateUser](
validator.Options{TagName: "binding", StrictMissingFields: true},
))
func create(c *gin.Context) {
var req CreateUser
if err := c.ShouldBindJSON(&req); err != nil {
if ve, ok := pedantigogin.AsValidationError(err); ok {
c.JSON(http.StatusBadRequest, ve.Errors)
return
}
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, req)
}
func main() {
pedantigogin.NewBinder()
r := gin.Default()
r.POST("/users", create)
_ = r.Run(":8080")
}Gin reads the binding tag, so the options set TagName: "binding". The StrictMissingFields: true setting matters. Passing Options{TagName: "binding"} alone replaces the defaults with a zero struct. Missing-field detection then turns off, and a missing required key passes.
The Gin plugin has two limits:
- Only JSON bodies get missing-field detection and defaults. For query, form, header and URI binding, only value constraints run, and a missing
requiredfield passes. - The module needs Go 1.25 or later. The Echo plugin needs Go 1.23 or later.
Versions to avoid
The go.mod file retracts two early v2 tags:
| Version | Problem |
|---|---|
| v2.0.0 | Published with a stale layout that the module proxy cached |
| v2.1.0 | The plugin module paths broke Go's major-version suffix rule, so its install instructions failed |
Use v2.1.3 or later. The first working Echo and Gin plugin tags are v2.1.1.
Learn more
The v1 to v2 migration guide has the full steps. The Echo and Gin plugin pages cover the binders. The source is on GitHub.
Related posts
pedantigo: Pydantic-inspired Go validation and LLM JSON Schema
pedantigo is an MIT-licensed Go library that unmarshals JSON into structs, enforces constraints from struct tags, and generates JSON Schema from the same structs.

multipay-india: one Go API for Cashfree and Razorpay
multipay-india is an open-source Go library that puts Indian payment gateways behind one API for orders, subscriptions, plan changes and webhooks.

Caching, Part 3: how Smritea uses smartcache
How Smritea uses its open-source smartcache library: write-then-evict, tenant-safe read-through, fail-open versus fail-closed choices, and per-app prefix eviction.




