[{"data":1,"prerenderedAt":2011},["ShallowReactive",2],{"navigation_docs_en":3,"-en-http-validation":342,"-en-http-validation-surround":2006},[4,45,61,96,132,166,196,217,241,265],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F10.reference",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F10.reference\u002F1.configuration","i-lucide-settings",{"title":57,"path":58,"stem":59,"icon":60},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F10.reference\u002F2.dependencies","i-lucide-package",{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[67,72,77,82,86,91],{"title":68,"path":69,"stem":70,"icon":71},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture","i-lucide-layers",{"title":73,"path":74,"stem":75,"icon":76},"Application lifecycle","\u002Fen\u002Fconcepts\u002Fapplication-lifecycle","en\u002F2.concepts\u002F2.application-lifecycle","i-lucide-power",{"title":78,"path":79,"stem":80,"icon":81},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F3.error-model","i-lucide-shield-alert",{"title":52,"path":83,"stem":84,"icon":85},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F4.configuration","i-lucide-settings-2",{"title":87,"path":88,"stem":89,"icon":90},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F5.codegen-pipeline","i-lucide-file-json",{"title":92,"path":93,"stem":94,"icon":95},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F6.design-patterns","i-lucide-puzzle",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":44},"HTTP & Routing","i-lucide-globe","\u002Fen\u002Fhttp","en\u002F3.http",[102,107,112,117,122,127],{"title":103,"path":104,"stem":105,"icon":106},"The server core","\u002Fen\u002Fhttp\u002Fserver","en\u002F3.http\u002F1.server","i-lucide-server",{"title":108,"path":109,"stem":110,"icon":111},"The Fiber engine","\u002Fen\u002Fhttp\u002Ffiber","en\u002F3.http\u002F2.fiber","i-lucide-zap",{"title":113,"path":114,"stem":115,"icon":116},"The chi engine","\u002Fen\u002Fhttp\u002Fchi","en\u002F3.http\u002F3.chi","i-lucide-route",{"title":118,"path":119,"stem":120,"icon":121},"Error responses","\u002Fen\u002Fhttp\u002Ferror-responses","en\u002F3.http\u002F4.error-responses","i-lucide-octagon-alert",{"title":123,"path":124,"stem":125,"icon":126},"Validation","\u002Fen\u002Fhttp\u002Fvalidation","en\u002F3.http\u002F5.validation","i-lucide-badge-check",{"title":128,"path":129,"stem":130,"icon":131},"Pagination","\u002Fen\u002Fhttp\u002Fpagination","en\u002F3.http\u002F6.pagination","i-lucide-list-ordered",{"title":133,"icon":134,"path":135,"stem":136,"children":137,"page":44},"Database","i-lucide-database","\u002Fen\u002Fdatabase","en\u002F4.database",[138,142,147,151,156,161],{"title":139,"path":140,"stem":141,"icon":134},"Overview","\u002Fen\u002Fdatabase\u002Foverview","en\u002F4.database\u002F1.overview",{"title":143,"path":144,"stem":145,"icon":146},"pgx","\u002Fen\u002Fdatabase\u002Fpgx","en\u002F4.database\u002F2.pgx","i-lucide-plug",{"title":148,"path":149,"stem":150,"icon":71},"bun","\u002Fen\u002Fdatabase\u002Fbun","en\u002F4.database\u002F3.bun",{"title":152,"path":153,"stem":154,"icon":155},"Transactions","\u002Fen\u002Fdatabase\u002Ftransactions","en\u002F4.database\u002F4.transactions","i-lucide-git-merge",{"title":157,"path":158,"stem":159,"icon":160},"Migrations","\u002Fen\u002Fdatabase\u002Fmigrations","en\u002F4.database\u002F5.migrations","i-lucide-file-stack",{"title":162,"path":163,"stem":164,"icon":165},"Seeders","\u002Fen\u002Fdatabase\u002Fseeding","en\u002F4.database\u002F6.seeding","i-lucide-sprout",{"title":167,"icon":168,"path":169,"stem":170,"children":171,"page":44},"Async & Background","i-lucide-workflow","\u002Fen\u002Fasync","en\u002F5.async",[172,176,181,186,191],{"title":173,"path":174,"stem":175,"icon":131},"Queue","\u002Fen\u002Fasync\u002Fqueue","en\u002F5.async\u002F1.queue",{"title":177,"path":178,"stem":179,"icon":180},"Events","\u002Fen\u002Fasync\u002Fevents","en\u002F5.async\u002F2.events","i-lucide-radio",{"title":182,"path":183,"stem":184,"icon":185},"Outbox","\u002Fen\u002Fasync\u002Foutbox","en\u002F5.async\u002F3.outbox","i-lucide-inbox",{"title":187,"path":188,"stem":189,"icon":190},"Scheduling","\u002Fen\u002Fasync\u002Fscheduler","en\u002F5.async\u002F4.scheduler","i-lucide-calendar-clock",{"title":192,"path":193,"stem":194,"icon":195},"Worker","\u002Fen\u002Fasync\u002Fworker","en\u002F5.async\u002F5.worker","i-lucide-cog",{"title":197,"icon":198,"path":199,"stem":200,"children":201,"page":44},"Security","i-lucide-shield-check","\u002Fen\u002Fsecurity","en\u002F6.security",[202,207,212],{"title":203,"path":204,"stem":205,"icon":206},"Authentication","\u002Fen\u002Fsecurity\u002Fauthentication","en\u002F6.security\u002F1.authentication","i-lucide-key-round",{"title":208,"path":209,"stem":210,"icon":211},"RBAC","\u002Fen\u002Fsecurity\u002Frbac","en\u002F6.security\u002F2.rbac","i-lucide-users",{"title":213,"path":214,"stem":215,"icon":216},"Policies","\u002Fen\u002Fsecurity\u002Fpolicies","en\u002F6.security\u002F3.policies","i-lucide-gavel",{"title":218,"icon":219,"path":220,"stem":221,"children":222,"page":44},"Observability","i-lucide-activity","\u002Fen\u002Fobservability","en\u002F7.observability",[223,226,231,236],{"title":139,"path":224,"stem":225,"icon":219},"\u002Fen\u002Fobservability\u002Foverview","en\u002F7.observability\u002F1.overview",{"title":227,"path":228,"stem":229,"icon":230},"Logging","\u002Fen\u002Fobservability\u002Flogging","en\u002F7.observability\u002F2.logging","i-lucide-scroll-text",{"title":232,"path":233,"stem":234,"icon":235},"OpenTelemetry","\u002Fen\u002Fobservability\u002Fopentelemetry","en\u002F7.observability\u002F3.opentelemetry","i-lucide-radar",{"title":237,"path":238,"stem":239,"icon":240},"Sentry","\u002Fen\u002Fobservability\u002Fsentry","en\u002F7.observability\u002F4.sentry","i-lucide-bug",{"title":242,"icon":243,"path":244,"stem":245,"children":246,"page":44},"Storage & Mail","i-lucide-hard-drive","\u002Fen\u002Fstorage-mail","en\u002F8.storage-mail",[247,251,256,261],{"title":248,"path":249,"stem":250,"icon":243},"Storage","\u002Fen\u002Fstorage-mail\u002Fstorage","en\u002F8.storage-mail\u002F1.storage",{"title":252,"path":253,"stem":254,"icon":255},"Email","\u002Fen\u002Fstorage-mail\u002Fmail","en\u002F8.storage-mail\u002F2.mail","i-lucide-mail",{"title":257,"path":258,"stem":259,"icon":260},"Notifications","\u002Fen\u002Fstorage-mail\u002Fnotifications","en\u002F8.storage-mail\u002F3.notifications","i-lucide-bell",{"title":262,"path":263,"stem":264,"icon":180},"Realtime","\u002Fen\u002Fstorage-mail\u002Frealtime","en\u002F8.storage-mail\u002F4.realtime",{"title":266,"icon":267,"path":268,"stem":269,"children":270,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F9.cli",[271,274,279,284,289,294,299,303,308,313,318,323,328,333,337],{"title":139,"path":272,"stem":273,"icon":267},"\u002Fen\u002Fcli\u002Foverview","en\u002F9.cli\u002F1.overview",{"title":275,"path":276,"stem":277,"icon":278},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F9.cli\u002F10.add-db","i-lucide-database-zap",{"title":280,"path":281,"stem":282,"icon":283},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F9.cli\u002F11.add-compose","i-lucide-container",{"title":285,"path":286,"stem":287,"icon":288},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F9.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":290,"path":291,"stem":292,"icon":293},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F9.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":295,"path":296,"stem":297,"icon":298},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F9.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":300,"path":301,"stem":302,"icon":165},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F9.cli\u002F15.add-seeder",{"title":304,"path":305,"stem":306,"icon":307},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F9.cli\u002F2.new-project","i-lucide-folder-plus",{"title":309,"path":310,"stem":311,"icon":312},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F9.cli\u002F3.new-module","i-lucide-blocks",{"title":314,"path":315,"stem":316,"icon":317},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F9.cli\u002F4.add-surface","i-lucide-layers-2",{"title":319,"path":320,"stem":321,"icon":322},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F9.cli\u002F5.add-core","i-lucide-box",{"title":324,"path":325,"stem":326,"icon":327},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F9.cli\u002F6.add-handler","i-lucide-webhook",{"title":329,"path":330,"stem":331,"icon":332},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F9.cli\u002F7.new-migration","i-lucide-file-plus",{"title":334,"path":335,"stem":336,"icon":195},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F9.cli\u002F8.worker-generators",{"title":338,"path":339,"stem":340,"icon":341},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F9.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"id":343,"title":123,"body":344,"description":1999,"extension":2000,"links":2001,"meta":2002,"navigation":2003,"path":124,"seo":2004,"stem":125,"__hash__":2005},"docs_en\u002Fen\u002F3.http\u002F5.validation.md",{"type":345,"value":346,"toc":1989},"minimark",[347,368,397,402,557,563,602,651,655,658,935,962,966,969,1039,1050,1347,1361,1447,1451,1462,1591,1696,1716,1720,1731,1846,1850,1859,1907,1916,1920,1943,1954,1958,1985],[348,349,350,351,358,359,363,364,367],"p",{},"Request validation in the kit is declarative: you write rules as tags on struct fields, and the chassis handles execution and error rendering. The engine is ",[352,353,357],"a",{"href":354,"rel":355},"https:\u002F\u002Fgithub.com\u002Fgo-playground\u002Fvalidator",[356],"nofollow","go-playground\u002Fvalidator v10"," (Go's de facto standard validator), and the ",[360,361,362],"code",{},"validate"," package wires it so that every failure becomes an ",[352,365,366],{"href":119},"RFC 9457 problem response"," with a per-field error list, with no handler code involved.",[369,370,375],"pre",{"className":371,"code":372,"language":373,"meta":374,"style":374},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fvalidate\"\n","go","",[360,376,377],{"__ignoreMap":374},[378,379,382,386,390,394],"span",{"class":380,"line":381},"line",1,[378,383,385],{"class":384},"s7zQu","import",[378,387,389],{"class":388},"sMK4o"," \"",[378,391,393],{"class":392},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fvalidate",[378,395,396],{"class":388},"\"\n",[398,399,401],"h2",{"id":400},"the-validator-type","The Validator type",[369,403,405],{"className":371,"code":404,"language":373,"meta":374,"style":374},"func New(opts ...Option) *Validator\n\nfunc (v *Validator) Validate(out any) error \u002F\u002F implements fiber.StructValidator\nfunc (v *Validator) Struct(s any) error     \u002F\u002F the same, for use outside the binding pipeline\n\nfunc Translate(verrs validator.ValidationErrors) []httperr.FieldError\n",[360,406,407,438,445,485,517,522],{"__ignoreMap":374},[378,408,409,412,416,419,423,426,429,432,435],{"class":380,"line":381},[378,410,411],{"class":388},"func",[378,413,415],{"class":414},"s2Zo4"," New",[378,417,418],{"class":388},"(",[378,420,422],{"class":421},"sHdIc","opts",[378,424,425],{"class":388}," ...",[378,427,428],{"class":392},"Option",[378,430,431],{"class":388},")",[378,433,434],{"class":388}," *",[378,436,437],{"class":392},"Validator\n",[378,439,441],{"class":380,"line":440},2,[378,442,444],{"emptyLinePlaceholder":443},true,"\n",[378,446,448,450,453,456,459,462,464,467,469,472,475,477,481],{"class":380,"line":447},3,[378,449,411],{"class":388},[378,451,452],{"class":388}," (",[378,454,455],{"class":421},"v ",[378,457,458],{"class":388},"*",[378,460,461],{"class":392},"Validator",[378,463,431],{"class":388},[378,465,466],{"class":414}," Validate",[378,468,418],{"class":388},[378,470,471],{"class":421},"out",[378,473,474],{"class":392}," any",[378,476,431],{"class":388},[378,478,480],{"class":479},"spNyl"," error",[378,482,484],{"class":483},"sHwdD"," \u002F\u002F implements fiber.StructValidator\n",[378,486,488,490,492,494,496,498,500,503,505,508,510,512,514],{"class":380,"line":487},4,[378,489,411],{"class":388},[378,491,452],{"class":388},[378,493,455],{"class":421},[378,495,458],{"class":388},[378,497,461],{"class":392},[378,499,431],{"class":388},[378,501,502],{"class":414}," Struct",[378,504,418],{"class":388},[378,506,507],{"class":421},"s",[378,509,474],{"class":392},[378,511,431],{"class":388},[378,513,480],{"class":479},[378,515,516],{"class":483},"     \u002F\u002F the same, for use outside the binding pipeline\n",[378,518,520],{"class":380,"line":519},5,[378,521,444],{"emptyLinePlaceholder":443},[378,523,525,527,530,532,535,538,541,544,546,549,552,554],{"class":380,"line":524},6,[378,526,411],{"class":388},[378,528,529],{"class":414}," Translate",[378,531,418],{"class":388},[378,533,534],{"class":421},"verrs",[378,536,537],{"class":392}," validator",[378,539,540],{"class":388},".",[378,542,543],{"class":392},"ValidationErrors",[378,545,431],{"class":388},[378,547,548],{"class":388}," []",[378,550,551],{"class":392},"httperr",[378,553,540],{"class":388},[378,555,556],{"class":392},"FieldError\n",[348,558,559,562],{},[360,560,561],{},"New"," builds the validator with two kit-fixed defaults:",[564,565,566,580],"ul",{},[567,568,569,575,576,579],"li",{},[570,571,572],"strong",{},[360,573,574],{},"WithRequiredStructEnabled()",": ",[360,577,578],{},"required"," semantics for nested structs follow the upcoming validator v11 default;",[567,581,582,585,586,589,590,593,594,597,598,601],{},[570,583,584],{},"json-tag field names",": field names in errors come from the ",[360,587,588],{},"json"," tag (",[360,591,592],{},"customerEmail",", not ",[360,595,596],{},"CustomerEmail","), with dotted paths for nested structs (",[360,599,600],{},"address.city",").",[348,603,604,605,608,609,612,613,616,617,620,621,624,625,627,628,630,631,630,634,630,637,630,640,630,643,646,647,650],{},"On failure, ",[360,606,607],{},"Validate","\u002F",[360,610,611],{},"Struct"," does not return a raw validator error but a ready ",[360,614,615],{},"*httperr.Problem"," (422), with the field errors translated into ",[360,618,619],{},"httperr.FieldError","s via ",[360,622,623],{},"Translate",": the error renderer has nothing left to do with it. ",[360,626,623],{}," writes human-readable messages for the common rules (",[360,629,578],{},", ",[360,632,633],{},"email",[360,635,636],{},"min",[360,638,639],{},"max",[360,641,642],{},"oneof",[360,644,645],{},"gt",", ...); unknown rules fall back to the ",[360,648,649],{},"failed rule \u003Ctag>=\u003Cparam>"," form.",[398,652,654],{"id":653},"wiring-per-engine","Wiring per engine",[348,656,657],{},"The same validator runs on both engines, with the same 422 output; only the execution point differs:",[659,660,661,824],"code-group",{},[369,662,665],{"className":371,"code":663,"filename":664,"language":373,"meta":374,"style":374},"\u002F\u002F fiberx.Run puts validate.New() into fiber.Config.StructValidator.\n\u002F\u002F From then on EVERY c.Bind().Body(&dto) call validates, both your\n\u002F\u002F hand-written handlers and the generated strict server (which binds\n\u002F\u002F through ctx.Bind().Body()). On failure the bind returns an error that\n\u002F\u002F becomes a 422 problem via the central error handler.\napp.Post(\"\u002Forders\", func(c fiber.Ctx) error {\n    var req placeOrderBody\n    if err := c.Bind().Body(&req); err != nil {\n        return err \u002F\u002F already a *httperr.Problem (422)\n    }\n    \u002F\u002F ...\n})\n","Fiber",[360,666,667,672,677,682,687,692,738,750,795,806,812,818],{"__ignoreMap":374},[378,668,669],{"class":380,"line":381},[378,670,671],{"class":483},"\u002F\u002F fiberx.Run puts validate.New() into fiber.Config.StructValidator.\n",[378,673,674],{"class":380,"line":440},[378,675,676],{"class":483},"\u002F\u002F From then on EVERY c.Bind().Body(&dto) call validates, both your\n",[378,678,679],{"class":380,"line":447},[378,680,681],{"class":483},"\u002F\u002F hand-written handlers and the generated strict server (which binds\n",[378,683,684],{"class":380,"line":487},[378,685,686],{"class":483},"\u002F\u002F through ctx.Bind().Body()). On failure the bind returns an error that\n",[378,688,689],{"class":380,"line":519},[378,690,691],{"class":483},"\u002F\u002F becomes a 422 problem via the central error handler.\n",[378,693,694,698,700,703,705,708,712,714,717,720,723,726,728,731,733,735],{"class":380,"line":524},[378,695,697],{"class":696},"sTEyZ","app",[378,699,540],{"class":388},[378,701,702],{"class":414},"Post",[378,704,418],{"class":388},[378,706,707],{"class":388},"\"",[378,709,711],{"class":710},"sfazB","\u002Forders",[378,713,707],{"class":388},[378,715,716],{"class":388},",",[378,718,719],{"class":388}," func(",[378,721,722],{"class":421},"c",[378,724,725],{"class":392}," fiber",[378,727,540],{"class":388},[378,729,730],{"class":392},"Ctx",[378,732,431],{"class":388},[378,734,480],{"class":479},[378,736,737],{"class":388}," {\n",[378,739,741,744,747],{"class":380,"line":740},7,[378,742,743],{"class":388},"    var",[378,745,746],{"class":696}," req ",[378,748,749],{"class":392},"placeOrderBody\n",[378,751,753,756,759,762,765,767,770,773,776,779,782,785,787,790,793],{"class":380,"line":752},8,[378,754,755],{"class":384},"    if",[378,757,758],{"class":696}," err ",[378,760,761],{"class":388},":=",[378,763,764],{"class":696}," c",[378,766,540],{"class":388},[378,768,769],{"class":414},"Bind",[378,771,772],{"class":388},"().",[378,774,775],{"class":414},"Body",[378,777,778],{"class":388},"(&",[378,780,781],{"class":696},"req",[378,783,784],{"class":388},");",[378,786,758],{"class":696},[378,788,789],{"class":388},"!=",[378,791,792],{"class":388}," nil",[378,794,737],{"class":388},[378,796,798,801,803],{"class":380,"line":797},9,[378,799,800],{"class":384},"        return",[378,802,758],{"class":696},[378,804,805],{"class":483},"\u002F\u002F already a *httperr.Problem (422)\n",[378,807,809],{"class":380,"line":808},10,[378,810,811],{"class":388},"    }\n",[378,813,815],{"class":380,"line":814},11,[378,816,817],{"class":483},"    \u002F\u002F ...\n",[378,819,821],{"class":380,"line":820},12,[378,822,823],{"class":388},"})\n",[369,825,828],{"className":371,"code":826,"filename":827,"language":373,"meta":374,"style":374},"\u002F\u002F The net\u002Fhttp strict server decodes with json.Decoder, without\n\u002F\u002F validation, so there, validation is strict middleware: chix.StrictValidator\n\u002F\u002F validates the fully bound request object (parameters + body) before the\n\u002F\u002F handler. The generated register.go wires it automatically:\nshopapigen.NewStrictHandlerWithOptions(apiHandler,\n    []shopapigen.StrictMiddlewareFunc{\n        chix.StrictValidator[shopapigen.StrictHandlerFunc](nil),\n        \u002F\u002F ...\n    },\n    shopapigen.StrictHTTPServerOptions{ \u002F* httperr hooks *\u002F })\n","chi",[360,829,830,835,840,845,850,868,883,906,911,916],{"__ignoreMap":374},[378,831,832],{"class":380,"line":381},[378,833,834],{"class":483},"\u002F\u002F The net\u002Fhttp strict server decodes with json.Decoder, without\n",[378,836,837],{"class":380,"line":440},[378,838,839],{"class":483},"\u002F\u002F validation, so there, validation is strict middleware: chix.StrictValidator\n",[378,841,842],{"class":380,"line":447},[378,843,844],{"class":483},"\u002F\u002F validates the fully bound request object (parameters + body) before the\n",[378,846,847],{"class":380,"line":487},[378,848,849],{"class":483},"\u002F\u002F handler. The generated register.go wires it automatically:\n",[378,851,852,855,857,860,862,865],{"class":380,"line":519},[378,853,854],{"class":696},"shopapigen",[378,856,540],{"class":388},[378,858,859],{"class":414},"NewStrictHandlerWithOptions",[378,861,418],{"class":388},[378,863,864],{"class":696},"apiHandler",[378,866,867],{"class":388},",\n",[378,869,870,873,875,877,880],{"class":380,"line":524},[378,871,872],{"class":388},"    []",[378,874,854],{"class":392},[378,876,540],{"class":388},[378,878,879],{"class":392},"StrictMiddlewareFunc",[378,881,882],{"class":388},"{\n",[378,884,885,888,890,893,896,898,900,903],{"class":380,"line":740},[378,886,887],{"class":696},"        chix",[378,889,540],{"class":388},[378,891,892],{"class":414},"StrictValidator",[378,894,895],{"class":388},"[",[378,897,854],{"class":392},[378,899,540],{"class":388},[378,901,902],{"class":392},"StrictHandlerFunc",[378,904,905],{"class":388},"](nil),\n",[378,907,908],{"class":380,"line":752},[378,909,910],{"class":483},"        \u002F\u002F ...\n",[378,912,913],{"class":380,"line":797},[378,914,915],{"class":388},"    },\n",[378,917,918,921,923,926,929,932],{"class":380,"line":808},[378,919,920],{"class":392},"    shopapigen",[378,922,540],{"class":388},[378,924,925],{"class":392},"StrictHTTPServerOptions",[378,927,928],{"class":388},"{",[378,930,931],{"class":483}," \u002F* httperr hooks *\u002F",[378,933,934],{"class":388}," })\n",[348,936,937,938,941,942,945,946,949,950,953,954,957,958,540],{},"The ",[360,939,940],{},"nil"," argument on the chi side is deliberate: ",[360,943,944],{},"StrictValidator(nil)"," resolves the validator at request time: first looking for the one set via ",[360,947,948],{},"chix.WithValidator"," in the context, and only then falling back to ",[360,951,952],{},"validate.New()",". A single option in ",[360,955,956],{},"main.go"," thus applies to the whole application, with no edits to generated code. Details: ",[352,959,961],{"href":960},"\u002Fen\u002Fhttp\u002Fchi#strictvalidator-validation-before-the-handler","the chi engine",[398,963,965],{"id":964},"the-shop-the-placeorder-request","The shop: the PlaceOrder request",[348,967,968],{},"The order-placement body carries three rules:",[369,970,972],{"className":371,"code":971,"language":373,"meta":374,"style":374},"type placeOrderBody struct {\n    ProductID     string `json:\"productId\" validate:\"required,uuid4\"`\n    Quantity      int    `json:\"quantity\" validate:\"required,gt=0\"`\n    CustomerEmail string `json:\"customerEmail\" validate:\"required,email\"`\n}\n",[360,973,974,987,1004,1020,1034],{"__ignoreMap":374},[378,975,976,979,982,985],{"class":380,"line":381},[378,977,978],{"class":388},"type",[378,980,981],{"class":392}," placeOrderBody",[378,983,984],{"class":388}," struct",[378,986,737],{"class":388},[378,988,989,992,995,998,1001],{"class":380,"line":440},[378,990,991],{"class":696},"    ProductID     ",[378,993,994],{"class":479},"string",[378,996,997],{"class":388}," `",[378,999,1000],{"class":710},"json:\"productId\" validate:\"required,uuid4\"",[378,1002,1003],{"class":388},"`\n",[378,1005,1006,1009,1012,1015,1018],{"class":380,"line":447},[378,1007,1008],{"class":696},"    Quantity      ",[378,1010,1011],{"class":479},"int",[378,1013,1014],{"class":388},"    `",[378,1016,1017],{"class":710},"json:\"quantity\" validate:\"required,gt=0\"",[378,1019,1003],{"class":388},[378,1021,1022,1025,1027,1029,1032],{"class":380,"line":487},[378,1023,1024],{"class":696},"    CustomerEmail ",[378,1026,994],{"class":479},[378,1028,997],{"class":388},[378,1030,1031],{"class":710},"json:\"customerEmail\" validate:\"required,email\"",[378,1033,1003],{"class":388},[378,1035,1036],{"class":380,"line":519},[378,1037,1038],{"class":388},"}\n",[348,1040,1041,1042,1045,1046,1049],{},"A request violating all three (",[360,1043,1044],{},"quantity: 0",", a malformed email, a missing ",[360,1047,1048],{},"productId",") gets this response, regardless of engine:",[369,1051,1054],{"className":1052,"code":1053,"language":588,"meta":374,"style":374},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"type\": \"about:blank\",\n  \"title\": \"Unprocessable Entity\",\n  \"status\": 422,\n  \"detail\": \"One or more fields failed validation.\",\n  \"instance\": \"\u002Fapi\u002Fv1\u002Fshop\u002Forders\",\n  \"errors\": [\n    { \"field\": \"productId\", \"rule\": \"required\", \"message\": \"is required\" },\n    { \"field\": \"quantity\", \"rule\": \"gt\", \"message\": \"must be greater than 0\" },\n    { \"field\": \"customerEmail\", \"rule\": \"email\", \"message\": \"must be a valid email address\" }\n  ]\n}\n",[360,1055,1056,1060,1081,1101,1118,1138,1158,1172,1230,1284,1338,1343],{"__ignoreMap":374},[378,1057,1058],{"class":380,"line":381},[378,1059,882],{"class":388},[378,1061,1062,1065,1067,1069,1072,1074,1077,1079],{"class":380,"line":440},[378,1063,1064],{"class":388},"  \"",[378,1066,978],{"class":479},[378,1068,707],{"class":388},[378,1070,1071],{"class":388},":",[378,1073,389],{"class":388},[378,1075,1076],{"class":710},"about:blank",[378,1078,707],{"class":388},[378,1080,867],{"class":388},[378,1082,1083,1085,1088,1090,1092,1094,1097,1099],{"class":380,"line":447},[378,1084,1064],{"class":388},[378,1086,1087],{"class":479},"title",[378,1089,707],{"class":388},[378,1091,1071],{"class":388},[378,1093,389],{"class":388},[378,1095,1096],{"class":710},"Unprocessable Entity",[378,1098,707],{"class":388},[378,1100,867],{"class":388},[378,1102,1103,1105,1108,1110,1112,1116],{"class":380,"line":487},[378,1104,1064],{"class":388},[378,1106,1107],{"class":479},"status",[378,1109,707],{"class":388},[378,1111,1071],{"class":388},[378,1113,1115],{"class":1114},"sbssI"," 422",[378,1117,867],{"class":388},[378,1119,1120,1122,1125,1127,1129,1131,1134,1136],{"class":380,"line":519},[378,1121,1064],{"class":388},[378,1123,1124],{"class":479},"detail",[378,1126,707],{"class":388},[378,1128,1071],{"class":388},[378,1130,389],{"class":388},[378,1132,1133],{"class":710},"One or more fields failed validation.",[378,1135,707],{"class":388},[378,1137,867],{"class":388},[378,1139,1140,1142,1145,1147,1149,1151,1154,1156],{"class":380,"line":524},[378,1141,1064],{"class":388},[378,1143,1144],{"class":479},"instance",[378,1146,707],{"class":388},[378,1148,1071],{"class":388},[378,1150,389],{"class":388},[378,1152,1153],{"class":710},"\u002Fapi\u002Fv1\u002Fshop\u002Forders",[378,1155,707],{"class":388},[378,1157,867],{"class":388},[378,1159,1160,1162,1165,1167,1169],{"class":380,"line":740},[378,1161,1064],{"class":388},[378,1163,1164],{"class":479},"errors",[378,1166,707],{"class":388},[378,1168,1071],{"class":388},[378,1170,1171],{"class":388}," [\n",[378,1173,1174,1177,1179,1182,1184,1186,1188,1190,1192,1194,1196,1199,1201,1203,1205,1207,1209,1211,1213,1216,1218,1220,1222,1225,1227],{"class":380,"line":752},[378,1175,1176],{"class":388},"    {",[378,1178,389],{"class":388},[378,1180,1181],{"class":392},"field",[378,1183,707],{"class":388},[378,1185,1071],{"class":388},[378,1187,389],{"class":388},[378,1189,1048],{"class":710},[378,1191,707],{"class":388},[378,1193,716],{"class":388},[378,1195,389],{"class":388},[378,1197,1198],{"class":392},"rule",[378,1200,707],{"class":388},[378,1202,1071],{"class":388},[378,1204,389],{"class":388},[378,1206,578],{"class":710},[378,1208,707],{"class":388},[378,1210,716],{"class":388},[378,1212,389],{"class":388},[378,1214,1215],{"class":392},"message",[378,1217,707],{"class":388},[378,1219,1071],{"class":388},[378,1221,389],{"class":388},[378,1223,1224],{"class":710},"is required",[378,1226,707],{"class":388},[378,1228,1229],{"class":388}," },\n",[378,1231,1232,1234,1236,1238,1240,1242,1244,1247,1249,1251,1253,1255,1257,1259,1261,1263,1265,1267,1269,1271,1273,1275,1277,1280,1282],{"class":380,"line":797},[378,1233,1176],{"class":388},[378,1235,389],{"class":388},[378,1237,1181],{"class":392},[378,1239,707],{"class":388},[378,1241,1071],{"class":388},[378,1243,389],{"class":388},[378,1245,1246],{"class":710},"quantity",[378,1248,707],{"class":388},[378,1250,716],{"class":388},[378,1252,389],{"class":388},[378,1254,1198],{"class":392},[378,1256,707],{"class":388},[378,1258,1071],{"class":388},[378,1260,389],{"class":388},[378,1262,645],{"class":710},[378,1264,707],{"class":388},[378,1266,716],{"class":388},[378,1268,389],{"class":388},[378,1270,1215],{"class":392},[378,1272,707],{"class":388},[378,1274,1071],{"class":388},[378,1276,389],{"class":388},[378,1278,1279],{"class":710},"must be greater than 0",[378,1281,707],{"class":388},[378,1283,1229],{"class":388},[378,1285,1286,1288,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330,1333,1335],{"class":380,"line":808},[378,1287,1176],{"class":388},[378,1289,389],{"class":388},[378,1291,1181],{"class":392},[378,1293,707],{"class":388},[378,1295,1071],{"class":388},[378,1297,389],{"class":388},[378,1299,592],{"class":710},[378,1301,707],{"class":388},[378,1303,716],{"class":388},[378,1305,389],{"class":388},[378,1307,1198],{"class":392},[378,1309,707],{"class":388},[378,1311,1071],{"class":388},[378,1313,389],{"class":388},[378,1315,633],{"class":710},[378,1317,707],{"class":388},[378,1319,716],{"class":388},[378,1321,389],{"class":388},[378,1323,1215],{"class":392},[378,1325,707],{"class":388},[378,1327,1071],{"class":388},[378,1329,389],{"class":388},[378,1331,1332],{"class":710},"must be a valid email address",[378,1334,707],{"class":388},[378,1336,1337],{"class":388}," }\n",[378,1339,1340],{"class":380,"line":814},[378,1341,1342],{"class":388},"  ]\n",[378,1344,1345],{"class":380,"line":820},[378,1346,1038],{"class":388},[348,1348,937,1349,1351,1352,1354,1355,1357,1358,1360],{},[360,1350,1198],{}," is machine-readable (the frontend can branch on it per field), the ",[360,1353,1215],{}," is a human-readable default: the final, localized text is typically mapped by the client from the ",[360,1356,1181],{}," + ",[360,1359,1198],{}," pair.",[1362,1363,1365,1380,1440],"note",{"title":1364},"Where do tags on generated models come from?",[348,1366,1367,1368,1371,1372,1375,1376,1379],{},"On your hand-written structs (Fiber handler DTOs, service input) you write the tags yourself. For ",[352,1369,1370],{"href":88},"spec-first"," generated request models, the tag source is the OpenAPI ",[360,1373,1374],{},"x-oapi-codegen-extra-tags"," extension, which you attach to a field from TypeSpec with the ",[360,1377,1378],{},"@extension"," decorator:",[369,1381,1385],{"className":1382,"code":1383,"language":1384,"meta":374,"style":374},"language-tsp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","model PlaceOrderBody {\n  @extension(\"x-oapi-codegen-extra-tags\", #{ validate: \"required,gt=0\" })\n  quantity: int32;\n}\n","tsp",[360,1386,1387,1397,1423,1436],{"__ignoreMap":374},[378,1388,1389,1392,1395],{"class":380,"line":381},[378,1390,1391],{"class":1114},"model",[378,1393,1394],{"class":392}," PlaceOrderBody",[378,1396,737],{"class":388},[378,1398,1399,1403,1405,1408,1410,1413,1416,1418,1421],{"class":380,"line":440},[378,1400,1402],{"class":1401},"swJcz","  @extension",[378,1404,418],{"class":388},[378,1406,1407],{"class":710},"\"x-oapi-codegen-extra-tags\"",[378,1409,716],{"class":388},[378,1411,1412],{"class":388}," #{",[378,1414,1415],{"class":696}," validate",[378,1417,1071],{"class":388},[378,1419,1420],{"class":710}," \"required,gt=0\"",[378,1422,934],{"class":388},[378,1424,1425,1428,1430,1433],{"class":380,"line":447},[378,1426,1427],{"class":696},"  quantity",[378,1429,1071],{"class":388},[378,1431,1432],{"class":392}," int32",[378,1434,1435],{"class":388},";\n",[378,1437,1438],{"class":380,"line":487},[378,1439,1038],{"class":388},[348,1441,1442,1443,1446],{},"oapi-codegen emits a ",[360,1444,1445],{},"validate:\"required,gt=0\""," tag onto the generated field; from there, the pipelines above run on it just the same.",[398,1448,1450],{"id":1449},"custom-tags","Custom tags",[348,1452,1453,1454,1457,1458,1461],{},"Beyond the built-in rule set, you register your own with ",[360,1455,1456],{},"WithRegister"," and make it application-wide with the engine's ",[360,1459,1460],{},"WithValidator"," option:",[369,1463,1465],{"className":371,"code":1464,"language":373,"meta":374,"style":374},"v := validate.New(validate.WithRegister(func(v *validator.Validate) {\n    _ = v.RegisterValidation(\"slug\", func(fl validator.FieldLevel) bool {\n        return slugRe.MatchString(fl.Field().String())\n    })\n}))\n",[360,1466,1467,1506,1552,1581,1586],{"__ignoreMap":374},[378,1468,1469,1471,1473,1475,1477,1479,1481,1483,1485,1487,1490,1493,1495,1498,1500,1502,1504],{"class":380,"line":381},[378,1470,455],{"class":696},[378,1472,761],{"class":388},[378,1474,1415],{"class":696},[378,1476,540],{"class":388},[378,1478,561],{"class":414},[378,1480,418],{"class":388},[378,1482,362],{"class":696},[378,1484,540],{"class":388},[378,1486,1456],{"class":414},[378,1488,1489],{"class":388},"(func(",[378,1491,1492],{"class":421},"v",[378,1494,434],{"class":388},[378,1496,1497],{"class":392},"validator",[378,1499,540],{"class":388},[378,1501,607],{"class":392},[378,1503,431],{"class":388},[378,1505,737],{"class":388},[378,1507,1508,1511,1514,1517,1519,1522,1524,1526,1529,1531,1533,1535,1538,1540,1542,1545,1547,1550],{"class":380,"line":440},[378,1509,1510],{"class":696},"    _ ",[378,1512,1513],{"class":388},"=",[378,1515,1516],{"class":696}," v",[378,1518,540],{"class":388},[378,1520,1521],{"class":414},"RegisterValidation",[378,1523,418],{"class":388},[378,1525,707],{"class":388},[378,1527,1528],{"class":710},"slug",[378,1530,707],{"class":388},[378,1532,716],{"class":388},[378,1534,719],{"class":388},[378,1536,1537],{"class":421},"fl",[378,1539,537],{"class":392},[378,1541,540],{"class":388},[378,1543,1544],{"class":392},"FieldLevel",[378,1546,431],{"class":388},[378,1548,1549],{"class":479}," bool",[378,1551,737],{"class":388},[378,1553,1554,1556,1559,1561,1564,1566,1568,1570,1573,1575,1578],{"class":380,"line":447},[378,1555,800],{"class":384},[378,1557,1558],{"class":696}," slugRe",[378,1560,540],{"class":388},[378,1562,1563],{"class":414},"MatchString",[378,1565,418],{"class":388},[378,1567,1537],{"class":696},[378,1569,540],{"class":388},[378,1571,1572],{"class":414},"Field",[378,1574,772],{"class":388},[378,1576,1577],{"class":414},"String",[378,1579,1580],{"class":388},"())\n",[378,1582,1583],{"class":380,"line":487},[378,1584,1585],{"class":388},"    })\n",[378,1587,1588],{"class":380,"line":519},[378,1589,1590],{"class":388},"}))\n",[659,1592,1593,1648],{},[369,1594,1596],{"className":371,"code":1595,"filename":664,"language":373,"meta":374,"style":374},"err := fiberx.Run(ctx, cfg.Server, register, fiberx.WithValidator(v))\n",[360,1597,1598],{"__ignoreMap":374},[378,1599,1600,1603,1605,1608,1610,1613,1615,1618,1620,1623,1625,1628,1630,1633,1635,1637,1639,1641,1643,1645],{"class":380,"line":381},[378,1601,1602],{"class":696},"err ",[378,1604,761],{"class":388},[378,1606,1607],{"class":696}," fiberx",[378,1609,540],{"class":388},[378,1611,1612],{"class":414},"Run",[378,1614,418],{"class":388},[378,1616,1617],{"class":696},"ctx",[378,1619,716],{"class":388},[378,1621,1622],{"class":696}," cfg",[378,1624,540],{"class":388},[378,1626,1627],{"class":696},"Server",[378,1629,716],{"class":388},[378,1631,1632],{"class":696}," register",[378,1634,716],{"class":388},[378,1636,1607],{"class":696},[378,1638,540],{"class":388},[378,1640,1460],{"class":414},[378,1642,418],{"class":388},[378,1644,1492],{"class":696},[378,1646,1647],{"class":388},"))\n",[369,1649,1651],{"className":371,"code":1650,"filename":827,"language":373,"meta":374,"style":374},"err := chix.Run(ctx, cfg.Server, register, chix.WithValidator(v))\n",[360,1652,1653],{"__ignoreMap":374},[378,1654,1655,1657,1659,1662,1664,1666,1668,1670,1672,1674,1676,1678,1680,1682,1684,1686,1688,1690,1692,1694],{"class":380,"line":381},[378,1656,1602],{"class":696},[378,1658,761],{"class":388},[378,1660,1661],{"class":696}," chix",[378,1663,540],{"class":388},[378,1665,1612],{"class":414},[378,1667,418],{"class":388},[378,1669,1617],{"class":696},[378,1671,716],{"class":388},[378,1673,1622],{"class":696},[378,1675,540],{"class":388},[378,1677,1627],{"class":696},[378,1679,716],{"class":388},[378,1681,1632],{"class":696},[378,1683,716],{"class":388},[378,1685,1661],{"class":696},[378,1687,540],{"class":388},[378,1689,1460],{"class":414},[378,1691,418],{"class":388},[378,1693,1492],{"class":696},[378,1695,1647],{"class":388},[348,1697,1698,1699,1702,1703,1705,1706,1708,1709,1711,1712,1715],{},"From then on the ",[360,1700,1701],{},"validate:\"slug\""," tag works everywhere: in bind-time validation, in the ",[360,1704,892],{}," and in manual ",[360,1707,611],{}," calls. A custom tag's message gets ",[360,1710,623],{},"'s fallback form (",[360,1713,1714],{},"failed rule slug","); if you need something nicer, map it on the client side.",[398,1717,1719],{"id":1718},"customizing-field-names","Customizing field names",[348,1721,1722,1723,1726,1727,1730],{},"The default json-tag naming can be replaced with ",[360,1724,1725],{},"WithTagNameFunc",", for instance when you want the ",[360,1728,1729],{},"form"," tag in errors:",[369,1732,1734],{"className":371,"code":1733,"language":373,"meta":374,"style":374},"v := validate.New(validate.WithTagNameFunc(func(field reflect.StructField) string {\n    name, _, _ := strings.Cut(field.Tag.Get(\"form\"), \",\")\n    return name\n}))\n",[360,1735,1736,1775,1834,1842],{"__ignoreMap":374},[378,1737,1738,1740,1742,1744,1746,1748,1750,1752,1754,1756,1758,1760,1763,1765,1768,1770,1773],{"class":380,"line":381},[378,1739,455],{"class":696},[378,1741,761],{"class":388},[378,1743,1415],{"class":696},[378,1745,540],{"class":388},[378,1747,561],{"class":414},[378,1749,418],{"class":388},[378,1751,362],{"class":696},[378,1753,540],{"class":388},[378,1755,1725],{"class":414},[378,1757,1489],{"class":388},[378,1759,1181],{"class":421},[378,1761,1762],{"class":392}," reflect",[378,1764,540],{"class":388},[378,1766,1767],{"class":392},"StructField",[378,1769,431],{"class":388},[378,1771,1772],{"class":479}," string",[378,1774,737],{"class":388},[378,1776,1777,1780,1782,1785,1787,1790,1792,1795,1797,1800,1802,1804,1806,1809,1811,1814,1816,1818,1820,1822,1825,1827,1829,1831],{"class":380,"line":440},[378,1778,1779],{"class":696},"    name",[378,1781,716],{"class":388},[378,1783,1784],{"class":696}," _",[378,1786,716],{"class":388},[378,1788,1789],{"class":696}," _ ",[378,1791,761],{"class":388},[378,1793,1794],{"class":696}," strings",[378,1796,540],{"class":388},[378,1798,1799],{"class":414},"Cut",[378,1801,418],{"class":388},[378,1803,1181],{"class":696},[378,1805,540],{"class":388},[378,1807,1808],{"class":696},"Tag",[378,1810,540],{"class":388},[378,1812,1813],{"class":414},"Get",[378,1815,418],{"class":388},[378,1817,707],{"class":388},[378,1819,1729],{"class":710},[378,1821,707],{"class":388},[378,1823,1824],{"class":388},"),",[378,1826,389],{"class":388},[378,1828,716],{"class":710},[378,1830,707],{"class":388},[378,1832,1833],{"class":388},")\n",[378,1835,1836,1839],{"class":380,"line":447},[378,1837,1838],{"class":384},"    return",[378,1840,1841],{"class":696}," name\n",[378,1843,1844],{"class":380,"line":487},[378,1845,1590],{"class":388},[398,1847,1849],{"id":1848},"outside-the-binding-pipeline","Outside the binding pipeline",[348,1851,1852,1854,1855,1858],{},[360,1853,611],{}," returns the same error shape anywhere, for checking service input, ",[352,1856,1857],{"href":83},"configuration"," or worker payloads:",[369,1860,1862],{"className":371,"code":1861,"language":373,"meta":374,"style":374},"if err := v.Struct(input); err != nil {\n    return err \u002F\u002F already a *httperr.Problem (422), ready for the handler chain to render\n}\n",[360,1863,1864,1894,1903],{"__ignoreMap":374},[378,1865,1866,1869,1871,1873,1875,1877,1879,1881,1884,1886,1888,1890,1892],{"class":380,"line":381},[378,1867,1868],{"class":384},"if",[378,1870,758],{"class":696},[378,1872,761],{"class":388},[378,1874,1516],{"class":696},[378,1876,540],{"class":388},[378,1878,611],{"class":414},[378,1880,418],{"class":388},[378,1882,1883],{"class":696},"input",[378,1885,784],{"class":388},[378,1887,758],{"class":696},[378,1889,789],{"class":388},[378,1891,792],{"class":388},[378,1893,737],{"class":388},[378,1895,1896,1898,1900],{"class":380,"line":440},[378,1897,1838],{"class":384},[378,1899,758],{"class":696},[378,1901,1902],{"class":483},"\u002F\u002F already a *httperr.Problem (422), ready for the handler chain to render\n",[378,1904,1905],{"class":380,"line":447},[378,1906,1038],{"class":388},[348,1908,1909,1910,1913,1914,540],{},"Raw ",[360,1911,1912],{},"validator.ValidationErrors"," (e.g. from a directly used validator instance) translate to the kit's field-error shape via ",[360,1915,623],{},[398,1917,1919],{"id":1918},"what-struct-tags-dont-cover","What struct tags don't cover",[348,1921,937,1922,1924,1925,1927,1928,1931,1932,1937,1938,1357,1940,1942],{},[360,1923,362],{}," struct tags (",[360,1926,1445],{},") cover syntactic\u002Fshape rules. Database-touching checks (e.g. uniqueness) are ",[570,1929,1930],{},"not"," a tag: they go to the service layer, surfacing as ",[352,1933,1934],{"href":79},[360,1935,1936],{},"errs"," errors.\n| custom rule class | ",[360,1939,1456],{},[360,1941,1521],{}," |",[348,1944,1945,1946,1949,1950,1953],{},"The main difference is one of philosophy: a FormRequest is a request class carrying rules, authorization and messages; here, tags validate ",[570,1947,1948],{},"shape only",". Authorization belongs to the ",[352,1951,1952],{"href":214},"policy layer",", business invariants (stock, uniqueness) to the service layer.",[398,1955,1957],{"id":1956},"patterns-used","Patterns used",[564,1959,1960,1972],{},[567,1961,1962,452,1965,1968,1969,540],{},[570,1963,1964],{},"Functional options directly on the wrapped type",[360,1966,1967],{},"Option func(*validator.Validate)","): ",[352,1970,92],{"href":1971},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#functional-options",[567,1973,1974,452,1977,575,1979,1981,1982,1984],{},[570,1975,1976],{},"Adapter + translation layer",[360,1978,623],{},[360,1980,1912],{}," → ",[360,1983,619],{},") between the validation library and the wire format.",[1986,1987,1988],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":374,"searchDepth":440,"depth":440,"links":1990},[1991,1992,1993,1994,1995,1996,1997,1998],{"id":400,"depth":440,"text":401},{"id":653,"depth":440,"text":654},{"id":964,"depth":440,"text":965},{"id":1449,"depth":440,"text":1450},{"id":1718,"depth":440,"text":1719},{"id":1848,"depth":440,"text":1849},{"id":1918,"depth":440,"text":1919},{"id":1956,"depth":440,"text":1957},"Struct-tag-based request validation with go-playground\u002Fvalidator, at bind time on Fiber, as strict middleware on chi, with 422 problem responses.","md",null,{},{"icon":126},{"title":123,"description":1999},"SObZNF0KxrYqlUCZDj4QUhWcjrT2uhGDXvXBc1fYYC4",[2007,2009],{"title":118,"path":119,"stem":120,"description":2008,"icon":121,"children":-1},"The httperr package, RFC 9457 problem+json for every error, through one central mapping, on both engines.",{"title":128,"path":129,"stem":130,"description":2010,"icon":131,"children":-1},"Offset and cursor (keyset) pagination with the paginate package, normalized parameters, typed page wrappers, opaque cursors.",1784668707601]