[{"data":1,"prerenderedAt":1737},["ShallowReactive",2],{"navigation":3,"\u002Fintegrations\u002Fweb\u002Ftower":335,"\u002Fintegrations\u002Fweb\u002Ftower-surround":1732},[4,27,73,95,121,135,305,331],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,14,18,22],{"title":11,"path":12,"stem":13},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction",{"title":15,"path":16,"stem":17},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":19,"path":20,"stem":21},"Quick start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start",{"title":23,"path":24,"stem":25},"MSRV","\u002Fgetting-started\u002Fmsrv","1.getting-started\u002F9.msrv",false,{"title":28,"icon":29,"path":30,"stem":31,"children":32,"page":26},"Schemas","i-lucide-shapes","\u002Fschemas","2.schemas",[33,37,41,45,49,53,57,61,65,69],{"title":34,"path":35,"stem":36},"Strings","\u002Fschemas\u002Fstrings","2.schemas\u002F1.strings",{"title":38,"path":39,"stem":40},"Custom rules","\u002Fschemas\u002Frules","2.schemas\u002F10.rules",{"title":42,"path":43,"stem":44},"Numbers","\u002Fschemas\u002Fnumbers","2.schemas\u002F2.numbers",{"title":46,"path":47,"stem":48},"Booleans, literals and enums","\u002Fschemas\u002Fprimitives","2.schemas\u002F3.primitives",{"title":50,"path":51,"stem":52},"Dates and times","\u002Fschemas\u002Fdates","2.schemas\u002F4.dates",{"title":54,"path":55,"stem":56},"Collections","\u002Fschemas\u002Fcollections","2.schemas\u002F5.collections",{"title":58,"path":59,"stem":60},"Dynamic objects","\u002Fschemas\u002Fobjects","2.schemas\u002F6.objects",{"title":62,"path":63,"stem":64},"Modifiers","\u002Fschemas\u002Fmodifiers","2.schemas\u002F7.modifiers",{"title":66,"path":67,"stem":68},"Combinators","\u002Fschemas\u002Fcombinators","2.schemas\u002F8.combinators",{"title":70,"path":71,"stem":72},"Other types","\u002Fschemas\u002Fspecial-types","2.schemas\u002F9.special-types",{"title":74,"icon":75,"path":76,"stem":77,"children":78,"page":26},"Structs","i-lucide-braces","\u002Fstructs","3.structs",[79,83,87,91],{"title":80,"path":81,"stem":82},"schema! macro","\u002Fstructs\u002Fschema-macro","3.structs\u002F1.schema-macro",{"title":84,"path":85,"stem":86},"#[derive(Validate)]","\u002Fstructs\u002Fderive","3.structs\u002F2.derive",{"title":88,"path":89,"stem":90},"Parse vs validate","\u002Fstructs\u002Fparse-vs-validate","3.structs\u002F3.parse-vs-validate",{"title":92,"path":93,"stem":94},"Lenient parsing","\u002Fstructs\u002Flenient","3.structs\u002F4.lenient",{"title":96,"icon":97,"path":98,"stem":99,"children":100,"page":26},"Errors","i-lucide-triangle-alert","\u002Ferrors","4.errors",[101,105,109,113,117],{"title":102,"path":103,"stem":104},"Error model","\u002Ferrors\u002Foverview","4.errors\u002F1.overview",{"title":106,"path":107,"stem":108},"Issue codes","\u002Ferrors\u002Fissue-codes","4.errors\u002F2.issue-codes",{"title":110,"path":111,"stem":112},"Formatting","\u002Ferrors\u002Fformatting","4.errors\u002F3.formatting",{"title":114,"path":115,"stem":116},"Custom messages","\u002Ferrors\u002Fcustom-messages","4.errors\u002F4.custom-messages",{"title":118,"path":119,"stem":120},"Translations","\u002Ferrors\u002Fi18n","4.errors\u002F5.i18n",{"title":122,"icon":123,"path":124,"stem":125,"children":126,"page":26},"OpenAPI","i-lucide-file-json","\u002Fopenapi","5.openapi",[127,131],{"title":128,"path":129,"stem":130},"JSON Schema and OpenAPI","\u002Fopenapi\u002Fjson-schema","5.openapi\u002F1.json-schema",{"title":132,"path":133,"stem":134},"Schema diff","\u002Fopenapi\u002Fdiff","5.openapi\u002F2.diff",{"title":136,"icon":137,"path":138,"stem":139,"children":140,"page":26},"Integrations","i-lucide-plug","\u002Fintegrations","6.integrations",[141,191,209,223,245,259,273,291],{"title":142,"icon":143,"path":144,"stem":145,"children":146,"page":26},"Web frameworks","i-lucide-globe","\u002Fintegrations\u002Fweb","6.integrations\u002F1.web",[147,151,155,159,163,167,171,175,179,183,187],{"title":148,"path":149,"stem":150},"Web adapters overview","\u002Fintegrations\u002Fweb\u002Foverview","6.integrations\u002F1.web\u002F01.overview",{"title":152,"path":153,"stem":154},"vld-axum","\u002Fintegrations\u002Fweb\u002Faxum","6.integrations\u002F1.web\u002F02.axum",{"title":156,"path":157,"stem":158},"vld-actix","\u002Fintegrations\u002Fweb\u002Factix","6.integrations\u002F1.web\u002F03.actix",{"title":160,"path":161,"stem":162},"vld-ntex","\u002Fintegrations\u002Fweb\u002Fntex","6.integrations\u002F1.web\u002F04.ntex",{"title":164,"path":165,"stem":166},"vld-poem","\u002Fintegrations\u002Fweb\u002Fpoem","6.integrations\u002F1.web\u002F05.poem",{"title":168,"path":169,"stem":170},"vld-rama","\u002Fintegrations\u002Fweb\u002Frama","6.integrations\u002F1.web\u002F06.rama",{"title":172,"path":173,"stem":174},"vld-rocket","\u002Fintegrations\u002Fweb\u002Frocket","6.integrations\u002F1.web\u002F07.rocket",{"title":176,"path":177,"stem":178},"vld-salvo","\u002Fintegrations\u002Fweb\u002Fsalvo","6.integrations\u002F1.web\u002F08.salvo",{"title":180,"path":181,"stem":182},"vld-tower","\u002Fintegrations\u002Fweb\u002Ftower","6.integrations\u002F1.web\u002F09.tower",{"title":184,"path":185,"stem":186},"vld-warp","\u002Fintegrations\u002Fweb\u002Fwarp","6.integrations\u002F1.web\u002F10.warp",{"title":188,"path":189,"stem":190},"vld-tonic","\u002Fintegrations\u002Fweb\u002Ftonic","6.integrations\u002F1.web\u002F11.tonic",{"title":192,"icon":193,"path":194,"stem":195,"children":196,"page":26},"OpenAPI and JSON Schema","i-lucide-file-code","\u002Fintegrations\u002Fopenapi","6.integrations\u002F2.openapi",[197,201,205],{"title":198,"path":199,"stem":200},"vld-utoipa","\u002Fintegrations\u002Fopenapi\u002Futoipa","6.integrations\u002F2.openapi\u002F1.utoipa",{"title":202,"path":203,"stem":204},"vld-schemars","\u002Fintegrations\u002Fopenapi\u002Fschemars","6.integrations\u002F2.openapi\u002F2.schemars",{"title":206,"path":207,"stem":208},"vld-aide","\u002Fintegrations\u002Fopenapi\u002Faide","6.integrations\u002F2.openapi\u002F3.aide",{"title":210,"icon":211,"path":212,"stem":213,"children":214,"page":26},"Codegen and test data","i-lucide-wand","\u002Fintegrations\u002Fcodegen","6.integrations\u002F3.codegen",[215,219],{"title":216,"path":217,"stem":218},"vld-ts","\u002Fintegrations\u002Fcodegen\u002Fts","6.integrations\u002F3.codegen\u002F1.ts",{"title":220,"path":221,"stem":222},"vld-fake","\u002Fintegrations\u002Fcodegen\u002Ffake","6.integrations\u002F3.codegen\u002F2.fake",{"title":224,"icon":225,"path":226,"stem":227,"children":228,"page":26},"Databases","i-lucide-database","\u002Fintegrations\u002Fdatabase","6.integrations\u002F4.database",[229,233,237,241],{"title":230,"path":231,"stem":232},"vld-sqlx","\u002Fintegrations\u002Fdatabase\u002Fsqlx","6.integrations\u002F4.database\u002F1.sqlx",{"title":234,"path":235,"stem":236},"vld-diesel","\u002Fintegrations\u002Fdatabase\u002Fdiesel","6.integrations\u002F4.database\u002F2.diesel",{"title":238,"path":239,"stem":240},"vld-sea","\u002Fintegrations\u002Fdatabase\u002Fsea-orm","6.integrations\u002F4.database\u002F3.sea-orm",{"title":242,"path":243,"stem":244},"vld-surrealdb","\u002Fintegrations\u002Fdatabase\u002Fsurrealdb","6.integrations\u002F4.database\u002F4.surrealdb",{"title":246,"icon":247,"path":248,"stem":249,"children":250,"page":26},"Messaging","i-lucide-mail","\u002Fintegrations\u002Fmessaging","6.integrations\u002F5.messaging",[251,255],{"title":252,"path":253,"stem":254},"vld-redis","\u002Fintegrations\u002Fmessaging\u002Fredis","6.integrations\u002F5.messaging\u002F1.redis",{"title":256,"path":257,"stem":258},"vld-lapin","\u002Fintegrations\u002Fmessaging\u002Flapin","6.integrations\u002F5.messaging\u002F2.lapin",{"title":260,"icon":261,"path":262,"stem":263,"children":264,"page":26},"Config and CLI","i-lucide-terminal","\u002Fintegrations\u002Fconfig-cli","6.integrations\u002F6.config-cli",[265,269],{"title":266,"path":267,"stem":268},"vld-config","\u002Fintegrations\u002Fconfig-cli\u002Fconfig","6.integrations\u002F6.config-cli\u002F1.config",{"title":270,"path":271,"stem":272},"vld-clap","\u002Fintegrations\u002Fconfig-cli\u002Fclap","6.integrations\u002F6.config-cli\u002F2.clap",{"title":274,"icon":275,"path":276,"stem":277,"children":278,"page":26},"UI frameworks","i-lucide-monitor","\u002Fintegrations\u002Fui","6.integrations\u002F7.ui",[279,283,287],{"title":280,"path":281,"stem":282},"vld-dioxus","\u002Fintegrations\u002Fui\u002Fdioxus","6.integrations\u002F7.ui\u002F1.dioxus",{"title":284,"path":285,"stem":286},"vld-leptos","\u002Fintegrations\u002Fui\u002Fleptos","6.integrations\u002F7.ui\u002F2.leptos",{"title":288,"path":289,"stem":290},"vld-tauri","\u002Fintegrations\u002Fui\u002Ftauri","6.integrations\u002F7.ui\u002F3.tauri",{"title":292,"icon":293,"path":294,"stem":295,"children":296,"page":26},"Shared crates","i-lucide-package","\u002Fintegrations\u002Fshared","6.integrations\u002F8.shared",[297,301],{"title":298,"path":299,"stem":300},"vld-http-common","\u002Fintegrations\u002Fshared\u002Fhttp-common","6.integrations\u002F8.shared\u002F1.http-common",{"title":302,"path":303,"stem":304},"vld-integration-common","\u002Fintegrations\u002Fshared\u002Fintegration-common","6.integrations\u002F8.shared\u002F2.integration-common",{"title":306,"icon":307,"path":308,"stem":309,"children":310,"page":26},"Guides","i-lucide-book-open","\u002Fguides","7.guides",[311,315,319,323,327],{"title":312,"path":313,"stem":314},"Migration","\u002Fguides\u002Fmigration","7.guides\u002F1.migration",{"title":316,"path":317,"stem":318},"Security notes","\u002Fguides\u002Fsecurity","7.guides\u002F2.security",{"title":320,"path":321,"stem":322},"Performance","\u002Fguides\u002Fperformance","7.guides\u002F3.performance",{"title":324,"path":325,"stem":326},"Contributing","\u002Fguides\u002Fcontributing","7.guides\u002F4.contributing",{"title":328,"path":329,"stem":330},"FAQ","\u002Fguides\u002Ffaq","7.guides\u002F5.faq",{"title":332,"path":333,"stem":334},"Changelog","\u002Fchangelog","9.changelog",{"id":336,"title":180,"body":337,"description":1718,"extension":1719,"links":1720,"meta":1729,"navigation":579,"path":181,"seo":1730,"stem":182,"__hash__":1731},"docs\u002F6.integrations\u002F1.web\u002F09.tower.md",{"type":338,"value":339,"toc":1709},"minimark",[340,384,389,449,459,463,1171,1176,1500,1506,1510,1608,1612,1660,1664,1705],[341,342,343,347,348,351,352,351,355,358,359,362,363,366,367,370,371,374,375,378,379,383],"p",{},[344,345,346],"code",{},"ValidateJsonLayer\u003CT>"," validates JSON request bodies before the inner service runs. It is framework-agnostic: it depends on ",[344,349,350],{},"tower-layer",", ",[344,353,354],{},"tower-service",[344,356,357],{},"http"," and ",[344,360,361],{},"http-body",", not on a web framework, so it works with an Axum ",[344,364,365],{},"Router",", a hyper service (via ",[344,368,369],{},"hyper-util","'s ",[344,372,373],{},"TowerToHyperService",") or a plain ",[344,376,377],{},"service_fn",". Error bodies follow the ",[380,381,382],"a",{"href":149},"web adapters overview",".",[385,386,388],"h2",{"id":387},"install","Install",[390,391,397],"pre",{"className":392,"code":393,"filename":394,"language":395,"meta":396,"style":396},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[dependencies]\nvld = \"0.5\"\nvld-tower = \"0.5\"\n","Cargo.toml","toml","",[344,398,399,415,435],{"__ignoreMap":396},[400,401,404,408,412],"span",{"class":402,"line":403},"line",1,[400,405,407],{"class":406},"sMK4o","[",[400,409,411],{"class":410},"sBMFI","dependencies",[400,413,414],{"class":406},"]\n",[400,416,418,422,425,428,432],{"class":402,"line":417},2,[400,419,421],{"class":420},"sTEyZ","vld ",[400,423,424],{"class":406},"=",[400,426,427],{"class":406}," \"",[400,429,431],{"class":430},"sfazB","0.5",[400,433,434],{"class":406},"\"\n",[400,436,438,441,443,445,447],{"class":402,"line":437},3,[400,439,440],{"class":420},"vld-tower ",[400,442,424],{"class":406},[400,444,427],{"class":406},[400,446,431],{"class":430},[400,448,434],{"class":406},[341,450,451,452,456,457,383],{},"No features. MSRV ",[453,454,455],"strong",{},"1.85",", see ",[380,458,23],{"href":24},[385,460,462],{"id":461},"example","Example",[390,464,468],{"className":465,"code":466,"language":467,"meta":396,"style":396},"language-rust shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","use bytes::Bytes;\nuse http::{Request, Response, StatusCode};\nuse http_body_util::Full;\nuse tower::{ServiceBuilder, ServiceExt};\nuse vld_tower::{validated, ValidateJsonLayer, ValidatedBody};\n\nvld::schema! {\n    #[derive(Debug, Clone)]\n    pub struct CreateUser {\n        pub name: String  => vld::string().min(2),\n        pub email: String => vld::string().email(),\n    }\n}\n\nasync fn handler(\n    req: Request\u003CValidatedBody\u003CFull\u003CBytes>>>,\n) -> Result\u003CResponse\u003CFull\u003CBytes>>, std::convert::Infallible> {\n    \u002F\u002F None: the request was not JSON and passed the layer unread.\n    let name = validated::\u003CCreateUser>(&req).map_or(\"not JSON\".into(), |u| u.name);\n    Ok(Response::new(Full::new(Bytes::from(name))))\n}\n\nlet svc = ServiceBuilder::new()\n    .layer(ValidateJsonLayer::\u003CCreateUser>::new())\n    .service_fn(handler);\n\nlet req = Request::post(\"\u002Fusers\")\n    .header(\"content-type\", \"application\u002Fjson\")\n    .body(Full::new(Bytes::from(r#\"{\"name\":\"A\",\"email\":\"bad\"}\"#)))\n    .unwrap();\nlet resp = svc.oneshot(req).await.unwrap();\nassert_eq!(resp.status(), StatusCode::UNPROCESSABLE_ENTITY);\n","rust",[344,469,470,488,515,529,549,574,581,596,619,634,674,703,709,715,720,735,763,809,816,886,925,930,935,956,982,996,1001,1030,1058,1099,1110,1144],{"__ignoreMap":396},[400,471,472,476,479,482,485],{"class":402,"line":403},[400,473,475],{"class":474},"sbssI","use",[400,477,478],{"class":410}," bytes",[400,480,481],{"class":406},"::",[400,483,484],{"class":410},"Bytes",[400,486,487],{"class":406},";\n",[400,489,490,492,495,498,501,504,507,509,512],{"class":402,"line":417},[400,491,475],{"class":474},[400,493,494],{"class":410}," http",[400,496,497],{"class":406},"::{",[400,499,500],{"class":410},"Request",[400,502,503],{"class":406},",",[400,505,506],{"class":410}," Response",[400,508,503],{"class":406},[400,510,511],{"class":410}," StatusCode",[400,513,514],{"class":406},"};\n",[400,516,517,519,522,524,527],{"class":402,"line":437},[400,518,475],{"class":474},[400,520,521],{"class":410}," http_body_util",[400,523,481],{"class":406},[400,525,526],{"class":410},"Full",[400,528,487],{"class":406},[400,530,532,534,537,539,542,544,547],{"class":402,"line":531},4,[400,533,475],{"class":474},[400,535,536],{"class":410}," tower",[400,538,497],{"class":406},[400,540,541],{"class":410},"ServiceBuilder",[400,543,503],{"class":406},[400,545,546],{"class":410}," ServiceExt",[400,548,514],{"class":406},[400,550,552,554,557,559,562,564,567,569,572],{"class":402,"line":551},5,[400,553,475],{"class":474},[400,555,556],{"class":410}," vld_tower",[400,558,497],{"class":406},[400,560,561],{"class":410},"validated",[400,563,503],{"class":406},[400,565,566],{"class":410}," ValidateJsonLayer",[400,568,503],{"class":406},[400,570,571],{"class":410}," ValidatedBody",[400,573,514],{"class":406},[400,575,577],{"class":402,"line":576},6,[400,578,580],{"emptyLinePlaceholder":579},true,"\n",[400,582,584,587,589,593],{"class":402,"line":583},7,[400,585,586],{"class":410},"vld",[400,588,481],{"class":406},[400,590,592],{"class":591},"s2Zo4","schema!",[400,594,595],{"class":406}," {\n",[400,597,599,602,605,608,611,613,616],{"class":402,"line":598},8,[400,600,601],{"class":406},"    #[",[400,603,604],{"class":420},"derive",[400,606,607],{"class":406},"(",[400,609,610],{"class":410},"Debug",[400,612,503],{"class":406},[400,614,615],{"class":410}," Clone",[400,617,618],{"class":406},")]\n",[400,620,622,626,629,632],{"class":402,"line":621},9,[400,623,625],{"class":624},"spNyl","    pub",[400,627,628],{"class":624}," struct",[400,630,631],{"class":410}," CreateUser",[400,633,595],{"class":406},[400,635,637,640,643,646,649,652,655,657,660,663,666,668,671],{"class":402,"line":636},10,[400,638,639],{"class":624},"        pub",[400,641,642],{"class":420}," name",[400,644,645],{"class":406},":",[400,647,648],{"class":410}," String",[400,650,651],{"class":406},"  =>",[400,653,654],{"class":410}," vld",[400,656,481],{"class":406},[400,658,659],{"class":591},"string",[400,661,662],{"class":406},"().",[400,664,665],{"class":591},"min",[400,667,607],{"class":406},[400,669,670],{"class":474},"2",[400,672,673],{"class":406},"),\n",[400,675,677,679,682,684,686,689,691,693,695,697,700],{"class":402,"line":676},11,[400,678,639],{"class":624},[400,680,681],{"class":420}," email",[400,683,645],{"class":406},[400,685,648],{"class":410},[400,687,688],{"class":406}," =>",[400,690,654],{"class":410},[400,692,481],{"class":406},[400,694,659],{"class":591},[400,696,662],{"class":406},[400,698,699],{"class":591},"email",[400,701,702],{"class":406},"(),\n",[400,704,706],{"class":402,"line":705},12,[400,707,708],{"class":406},"    }\n",[400,710,712],{"class":402,"line":711},13,[400,713,714],{"class":406},"}\n",[400,716,718],{"class":402,"line":717},14,[400,719,580],{"emptyLinePlaceholder":579},[400,721,723,726,729,732],{"class":402,"line":722},15,[400,724,725],{"class":474},"async",[400,727,728],{"class":474}," fn",[400,730,731],{"class":591}," handler",[400,733,734],{"class":406},"(\n",[400,736,738,741,743,746,749,752,754,756,758,760],{"class":402,"line":737},16,[400,739,740],{"class":420},"    req",[400,742,645],{"class":406},[400,744,745],{"class":410}," Request",[400,747,748],{"class":406},"\u003C",[400,750,751],{"class":410},"ValidatedBody",[400,753,748],{"class":406},[400,755,526],{"class":410},[400,757,748],{"class":406},[400,759,484],{"class":410},[400,761,762],{"class":406},">>>,\n",[400,764,766,769,772,775,777,780,782,784,786,788,791,794,796,799,801,804,807],{"class":402,"line":765},17,[400,767,768],{"class":406},")",[400,770,771],{"class":406}," ->",[400,773,774],{"class":410}," Result",[400,776,748],{"class":406},[400,778,779],{"class":410},"Response",[400,781,748],{"class":406},[400,783,526],{"class":410},[400,785,748],{"class":406},[400,787,484],{"class":410},[400,789,790],{"class":406},">>,",[400,792,793],{"class":420}," std",[400,795,481],{"class":406},[400,797,798],{"class":420},"convert",[400,800,481],{"class":406},[400,802,803],{"class":410},"Infallible",[400,805,806],{"class":406},">",[400,808,595],{"class":406},[400,810,812],{"class":402,"line":811},18,[400,813,815],{"class":814},"sHwdD","    \u002F\u002F None: the request was not JSON and passed the layer unread.\n",[400,817,819,822,825,827,830,833,836,839,842,845,848,850,853,856,858,860,863,866,869,872,875,878,880,883],{"class":402,"line":818},19,[400,820,821],{"class":624},"    let",[400,823,824],{"class":420}," name ",[400,826,424],{"class":406},[400,828,829],{"class":591}," validated",[400,831,832],{"class":406},"::\u003C",[400,834,835],{"class":410},"CreateUser",[400,837,838],{"class":406},">(&",[400,840,841],{"class":420},"req",[400,843,844],{"class":406},").",[400,846,847],{"class":591},"map_or",[400,849,607],{"class":406},[400,851,852],{"class":406},"\"",[400,854,855],{"class":430},"not JSON",[400,857,852],{"class":406},[400,859,383],{"class":406},[400,861,862],{"class":591},"into",[400,864,865],{"class":406},"(),",[400,867,868],{"class":406}," |",[400,870,871],{"class":420},"u",[400,873,874],{"class":406},"|",[400,876,877],{"class":420}," u",[400,879,383],{"class":406},[400,881,882],{"class":420},"name",[400,884,885],{"class":406},");\n",[400,887,889,892,894,896,898,901,903,905,907,909,911,913,915,918,920,922],{"class":402,"line":888},20,[400,890,891],{"class":410},"    Ok",[400,893,607],{"class":406},[400,895,779],{"class":410},[400,897,481],{"class":406},[400,899,900],{"class":591},"new",[400,902,607],{"class":406},[400,904,526],{"class":410},[400,906,481],{"class":406},[400,908,900],{"class":591},[400,910,607],{"class":406},[400,912,484],{"class":410},[400,914,481],{"class":406},[400,916,917],{"class":591},"from",[400,919,607],{"class":406},[400,921,882],{"class":420},[400,923,924],{"class":406},"))))\n",[400,926,928],{"class":402,"line":927},21,[400,929,714],{"class":406},[400,931,933],{"class":402,"line":932},22,[400,934,580],{"emptyLinePlaceholder":579},[400,936,938,941,944,946,949,951,953],{"class":402,"line":937},23,[400,939,940],{"class":624},"let",[400,942,943],{"class":420}," svc ",[400,945,424],{"class":406},[400,947,948],{"class":410}," ServiceBuilder",[400,950,481],{"class":406},[400,952,900],{"class":591},[400,954,955],{"class":406},"()\n",[400,957,959,962,965,967,970,972,974,977,979],{"class":402,"line":958},24,[400,960,961],{"class":406},"    .",[400,963,964],{"class":591},"layer",[400,966,607],{"class":406},[400,968,969],{"class":410},"ValidateJsonLayer",[400,971,832],{"class":406},[400,973,835],{"class":410},[400,975,976],{"class":406},">::",[400,978,900],{"class":591},[400,980,981],{"class":406},"())\n",[400,983,985,987,989,991,994],{"class":402,"line":984},25,[400,986,961],{"class":406},[400,988,377],{"class":591},[400,990,607],{"class":406},[400,992,993],{"class":420},"handler",[400,995,885],{"class":406},[400,997,999],{"class":402,"line":998},26,[400,1000,580],{"emptyLinePlaceholder":579},[400,1002,1004,1006,1009,1011,1013,1015,1018,1020,1022,1025,1027],{"class":402,"line":1003},27,[400,1005,940],{"class":624},[400,1007,1008],{"class":420}," req ",[400,1010,424],{"class":406},[400,1012,745],{"class":410},[400,1014,481],{"class":406},[400,1016,1017],{"class":591},"post",[400,1019,607],{"class":406},[400,1021,852],{"class":406},[400,1023,1024],{"class":430},"\u002Fusers",[400,1026,852],{"class":406},[400,1028,1029],{"class":406},")\n",[400,1031,1033,1035,1038,1040,1042,1045,1047,1049,1051,1054,1056],{"class":402,"line":1032},28,[400,1034,961],{"class":406},[400,1036,1037],{"class":591},"header",[400,1039,607],{"class":406},[400,1041,852],{"class":406},[400,1043,1044],{"class":430},"content-type",[400,1046,852],{"class":406},[400,1048,503],{"class":406},[400,1050,427],{"class":406},[400,1052,1053],{"class":430},"application\u002Fjson",[400,1055,852],{"class":406},[400,1057,1029],{"class":406},[400,1059,1061,1063,1066,1068,1070,1072,1074,1076,1078,1080,1082,1084,1087,1090,1093,1096],{"class":402,"line":1060},29,[400,1062,961],{"class":406},[400,1064,1065],{"class":591},"body",[400,1067,607],{"class":406},[400,1069,526],{"class":410},[400,1071,481],{"class":406},[400,1073,900],{"class":591},[400,1075,607],{"class":406},[400,1077,484],{"class":410},[400,1079,481],{"class":406},[400,1081,917],{"class":591},[400,1083,607],{"class":406},[400,1085,1086],{"class":430},"r",[400,1088,1089],{"class":406},"#\"",[400,1091,1092],{"class":430},"{\"name\":\"A\",\"email\":\"bad\"}",[400,1094,1095],{"class":406},"\"#",[400,1097,1098],{"class":406},")))\n",[400,1100,1102,1104,1107],{"class":402,"line":1101},30,[400,1103,961],{"class":406},[400,1105,1106],{"class":591},"unwrap",[400,1108,1109],{"class":406},"();\n",[400,1111,1113,1115,1118,1120,1123,1125,1128,1130,1132,1134,1138,1140,1142],{"class":402,"line":1112},31,[400,1114,940],{"class":624},[400,1116,1117],{"class":420}," resp ",[400,1119,424],{"class":406},[400,1121,1122],{"class":420}," svc",[400,1124,383],{"class":406},[400,1126,1127],{"class":591},"oneshot",[400,1129,607],{"class":406},[400,1131,841],{"class":420},[400,1133,844],{"class":406},[400,1135,1137],{"class":1136},"s7zQu","await",[400,1139,383],{"class":406},[400,1141,1106],{"class":591},[400,1143,1109],{"class":406},[400,1145,1147,1150,1152,1155,1157,1160,1162,1164,1166,1169],{"class":402,"line":1146},32,[400,1148,1149],{"class":591},"assert_eq!",[400,1151,607],{"class":406},[400,1153,1154],{"class":420},"resp",[400,1156,383],{"class":406},[400,1158,1159],{"class":591},"status",[400,1161,865],{"class":406},[400,1163,511],{"class":410},[400,1165,481],{"class":406},[400,1167,1168],{"class":420},"UNPROCESSABLE_ENTITY",[400,1170,885],{"class":406},[1172,1173,1175],"h3",{"id":1174},"with-axum","With Axum",[390,1177,1179],{"className":465,"code":1178,"language":467,"meta":396,"style":396},"use axum::http::StatusCode;\nuse axum::routing::post;\nuse axum::{Extension, Router};\nuse vld_tower::{ValidateJsonLayer, Validated};\n\nasync fn create(\n    user: Option\u003CExtension\u003CValidated\u003CCreateUser>>>,\n) -> Result\u003CString, (StatusCode, &'static str)> {\n    let Some(Extension(Validated(user))) = user else {\n        return Err((StatusCode::UNSUPPORTED_MEDIA_TYPE, \"expected JSON\"));\n    };\n    Ok(format!(\"created {}\", user.name))\n}\n\nlet app = Router::new()\n    .route(\"\u002Fusers\", post(create))\n    .layer(ValidateJsonLayer::\u003CCreateUser>::new());\n",[344,1180,1181,1199,1216,1234,1251,1255,1266,1291,1327,1361,1391,1396,1427,1431,1435,1452,1479],{"__ignoreMap":396},[400,1182,1183,1185,1188,1190,1192,1194,1197],{"class":402,"line":403},[400,1184,475],{"class":474},[400,1186,1187],{"class":410}," axum",[400,1189,481],{"class":406},[400,1191,357],{"class":410},[400,1193,481],{"class":406},[400,1195,1196],{"class":410},"StatusCode",[400,1198,487],{"class":406},[400,1200,1201,1203,1205,1207,1210,1212,1214],{"class":402,"line":417},[400,1202,475],{"class":474},[400,1204,1187],{"class":410},[400,1206,481],{"class":406},[400,1208,1209],{"class":410},"routing",[400,1211,481],{"class":406},[400,1213,1017],{"class":410},[400,1215,487],{"class":406},[400,1217,1218,1220,1222,1224,1227,1229,1232],{"class":402,"line":437},[400,1219,475],{"class":474},[400,1221,1187],{"class":410},[400,1223,497],{"class":406},[400,1225,1226],{"class":410},"Extension",[400,1228,503],{"class":406},[400,1230,1231],{"class":410}," Router",[400,1233,514],{"class":406},[400,1235,1236,1238,1240,1242,1244,1246,1249],{"class":402,"line":531},[400,1237,475],{"class":474},[400,1239,556],{"class":410},[400,1241,497],{"class":406},[400,1243,969],{"class":410},[400,1245,503],{"class":406},[400,1247,1248],{"class":410}," Validated",[400,1250,514],{"class":406},[400,1252,1253],{"class":402,"line":551},[400,1254,580],{"emptyLinePlaceholder":579},[400,1256,1257,1259,1261,1264],{"class":402,"line":576},[400,1258,725],{"class":474},[400,1260,728],{"class":474},[400,1262,1263],{"class":591}," create",[400,1265,734],{"class":406},[400,1267,1268,1271,1273,1276,1278,1280,1282,1285,1287,1289],{"class":402,"line":583},[400,1269,1270],{"class":420},"    user",[400,1272,645],{"class":406},[400,1274,1275],{"class":410}," Option",[400,1277,748],{"class":406},[400,1279,1226],{"class":410},[400,1281,748],{"class":406},[400,1283,1284],{"class":410},"Validated",[400,1286,748],{"class":406},[400,1288,835],{"class":410},[400,1290,762],{"class":406},[400,1292,1293,1295,1297,1299,1301,1304,1306,1309,1311,1313,1316,1319,1322,1325],{"class":402,"line":598},[400,1294,768],{"class":406},[400,1296,771],{"class":406},[400,1298,774],{"class":410},[400,1300,748],{"class":406},[400,1302,1303],{"class":410},"String",[400,1305,503],{"class":406},[400,1307,1308],{"class":406}," (",[400,1310,1196],{"class":410},[400,1312,503],{"class":406},[400,1314,1315],{"class":406}," &'",[400,1317,1318],{"class":410},"static",[400,1320,1321],{"class":410}," str",[400,1323,1324],{"class":406},")>",[400,1326,595],{"class":406},[400,1328,1329,1331,1334,1336,1338,1340,1342,1344,1347,1350,1353,1356,1359],{"class":402,"line":621},[400,1330,821],{"class":624},[400,1332,1333],{"class":410}," Some",[400,1335,607],{"class":406},[400,1337,1226],{"class":591},[400,1339,607],{"class":406},[400,1341,1284],{"class":591},[400,1343,607],{"class":406},[400,1345,1346],{"class":420},"user",[400,1348,1349],{"class":406},")))",[400,1351,1352],{"class":406}," =",[400,1354,1355],{"class":420}," user ",[400,1357,1358],{"class":1136},"else",[400,1360,595],{"class":406},[400,1362,1363,1366,1369,1372,1374,1376,1379,1381,1383,1386,1388],{"class":402,"line":636},[400,1364,1365],{"class":1136},"        return",[400,1367,1368],{"class":410}," Err",[400,1370,1371],{"class":406},"((",[400,1373,1196],{"class":410},[400,1375,481],{"class":406},[400,1377,1378],{"class":420},"UNSUPPORTED_MEDIA_TYPE",[400,1380,503],{"class":406},[400,1382,427],{"class":406},[400,1384,1385],{"class":430},"expected JSON",[400,1387,852],{"class":406},[400,1389,1390],{"class":406},"));\n",[400,1392,1393],{"class":402,"line":676},[400,1394,1395],{"class":406},"    };\n",[400,1397,1398,1400,1402,1405,1407,1409,1412,1415,1417,1420,1422,1424],{"class":402,"line":705},[400,1399,891],{"class":410},[400,1401,607],{"class":406},[400,1403,1404],{"class":591},"format!",[400,1406,607],{"class":406},[400,1408,852],{"class":406},[400,1410,1411],{"class":430},"created ",[400,1413,1414],{"class":406},"{}\"",[400,1416,503],{"class":406},[400,1418,1419],{"class":420}," user",[400,1421,383],{"class":406},[400,1423,882],{"class":420},[400,1425,1426],{"class":406},"))\n",[400,1428,1429],{"class":402,"line":711},[400,1430,714],{"class":406},[400,1432,1433],{"class":402,"line":717},[400,1434,580],{"emptyLinePlaceholder":579},[400,1436,1437,1439,1442,1444,1446,1448,1450],{"class":402,"line":722},[400,1438,940],{"class":624},[400,1440,1441],{"class":420}," app ",[400,1443,424],{"class":406},[400,1445,1231],{"class":410},[400,1447,481],{"class":406},[400,1449,900],{"class":591},[400,1451,955],{"class":406},[400,1453,1454,1456,1459,1461,1463,1465,1467,1469,1472,1474,1477],{"class":402,"line":737},[400,1455,961],{"class":406},[400,1457,1458],{"class":591},"route",[400,1460,607],{"class":406},[400,1462,852],{"class":406},[400,1464,1024],{"class":430},[400,1466,852],{"class":406},[400,1468,503],{"class":406},[400,1470,1471],{"class":591}," post",[400,1473,607],{"class":406},[400,1475,1476],{"class":420},"create",[400,1478,1426],{"class":406},[400,1480,1481,1483,1485,1487,1489,1491,1493,1495,1497],{"class":402,"line":765},[400,1482,961],{"class":406},[400,1484,964],{"class":591},[400,1486,607],{"class":406},[400,1488,969],{"class":410},[400,1490,832],{"class":406},[400,1492,835],{"class":410},[400,1494,976],{"class":406},[400,1496,900],{"class":591},[400,1498,1499],{"class":406},"());\n",[341,1501,1502,1503,1505],{},"For Axum handlers, ",[380,1504,152],{"href":153}," extractors are usually simpler; the layer fits when validation must happen before routing or in non-Axum stacks.",[385,1507,1509],{"id":1508},"api","API",[1511,1512,1513,1526],"table",{},[1514,1515,1516],"thead",{},[1517,1518,1519,1523],"tr",{},[1520,1521,1522],"th",{},"Item",[1520,1524,1525],{},"Purpose",[1527,1528,1529,1546,1556,1569,1582,1595],"tbody",{},[1517,1530,1531,1536],{},[1532,1533,1534],"td",{},[344,1535,346],{},[1532,1537,1538,1539,1542,1543],{},"The layer; ",[344,1540,1541],{},"new()"," (2 MiB limit) or ",[344,1544,1545],{},"with_limit(bytes)",[1517,1547,1548,1553],{},[1532,1549,1550],{},[344,1551,1552],{},"ValidateJsonService\u003CS, T>",[1532,1554,1555],{},"The service it produces",[1517,1557,1558,1563],{},[1532,1559,1560],{},[344,1561,1562],{},"Validated\u003CT>",[1532,1564,1565,1566,768],{},"Extension wrapper holding the validated value (derefs to ",[344,1567,1568],{},"T",[1517,1570,1571,1576],{},[1532,1572,1573],{},[344,1574,1575],{},"validated::\u003CT>(&req)",[1532,1577,1578,1581],{},[344,1579,1580],{},"Option\u003CT>"," from the request extensions",[1517,1583,1584,1589],{},[1532,1585,1586],{},[344,1587,1588],{},"ValidatedBody\u003CB>",[1532,1590,1591,1594],{},[344,1592,1593],{},"http_body_util::Either\u003CFull\u003CBytes>, B>",", the request and response body type",[1517,1596,1597,1602],{},[1532,1598,1599],{},[344,1600,1601],{},"prelude",[1532,1603,1604,1605],{},"All of the above plus ",[344,1606,1607],{},"vld::prelude::*",[385,1609,1611],{"id":1610},"status-codes","Status codes",[1511,1613,1614,1624],{},[1514,1615,1616],{},[1517,1617,1618,1621],{},[1520,1619,1620],{},"Situation",[1520,1622,1623],{},"Status",[1527,1625,1626,1634,1642],{},[1517,1627,1628,1631],{},[1532,1629,1630],{},"Validation failed, malformed JSON, body read error",[1532,1632,1633],{},"422",[1517,1635,1636,1639],{},[1532,1637,1638],{},"Body over the limit",[1532,1640,1641],{},"413",[1517,1643,1644,1657],{},[1532,1645,1646,1647,1650,1651,1653,1654,768],{},"Not JSON (",[344,1648,1649],{},"Content-Type"," is not ",[344,1652,1053],{}," \u002F ",[344,1655,1656],{},"application\u002F*+json",[1532,1658,1659],{},"passed through, no validation",[385,1661,1663],{"id":1662},"gotchas","Gotchas",[1665,1666,1667,1676,1694,1697],"ul",{},[1668,1669,1670,1673,1674,383],"li",{},[344,1671,1672],{},"validated()"," returns ",[344,1675,1580],{},[1668,1677,1678,1679,1682,1683,1686,1687,1690,1691,383],{},"The inner service receives ",[344,1680,1681],{},"Request\u003CValidatedBody\u003CB>>",": ",[344,1684,1685],{},"Left"," holds the buffered bytes of a validated JSON request, ",[344,1688,1689],{},"Right"," the untouched body of anything else. Responses are ",[344,1692,1693],{},"Response\u003CValidatedBody\u003CResBody>>",[1668,1695,1696],{},"The layer never returns an error of its own; its error type is the inner service's.",[1668,1698,1699,1701,1702,383],{},[344,1700,1568],{}," must be ",[344,1703,1704],{},"Clone + Send + Sync + 'static",[1706,1707,1708],"style",{},"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 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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .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}",{"title":396,"searchDepth":417,"depth":437,"links":1710},[1711,1712,1715,1716,1717],{"id":387,"depth":417,"text":388},{"id":461,"depth":417,"text":462,"children":1713},[1714],{"id":1174,"depth":437,"text":1175},{"id":1508,"depth":417,"text":1509},{"id":1610,"depth":417,"text":1611},{"id":1662,"depth":417,"text":1663},"A Tower layer that validates JSON request bodies for any http-based service.","md",[1721,1726],{"label":1722,"icon":1723,"to":1724,"target":1725},"crates.io","i-simple-icons-rust","https:\u002F\u002Fcrates.io\u002Fcrates\u002Fvld-tower","_blank",{"label":1727,"icon":307,"to":1728,"target":1725},"docs.rs","https:\u002F\u002Fdocs.rs\u002Fvld-tower",{},{"title":180,"description":1718},"tH5hTr95KIO70OaoAfskt0wnH66RrRUnOtmKfxu9Oj0",[1733,1735],{"title":176,"path":177,"stem":178,"description":1734,"children":-1},"Salvo 1.x extractors that validate request data with vld schemas.",{"title":184,"path":185,"stem":186,"description":1736,"children":-1},"Warp filters that validate request data with vld schemas, plus a JSON rejection handler.",1794036361542]