[{"data":1,"prerenderedAt":1927},["ShallowReactive",2],{"navigation_docs":3,"-core-routing":172,"-core-routing-surround":1922},[4,26,67,98,124,140,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":25},"Getting Started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-play",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Core","i-lucide-box","\u002Fcore","2.core",[32,37,42,47,52,57,62],{"title":33,"path":34,"stem":35,"icon":36},"Routing","\u002Fcore\u002Frouting","2.core\u002F1.routing","i-lucide-route",{"title":38,"path":39,"stem":40,"icon":41},"Handlers","\u002Fcore\u002Fhandlers","2.core\u002F2.handlers","i-lucide-braces",{"title":43,"path":44,"stem":45,"icon":46},"Request Binding","\u002Fcore\u002Frequest-binding","2.core\u002F3.request-binding","i-lucide-tags",{"title":48,"path":49,"stem":50,"icon":51},"Validation","\u002Fcore\u002Fvalidation","2.core\u002F4.validation","i-lucide-check-check",{"title":53,"path":54,"stem":55,"icon":56},"Context","\u002Fcore\u002Fcontext","2.core\u002F5.context","i-lucide-file-input",{"title":58,"path":59,"stem":60,"icon":61},"Errors","\u002Fcore\u002Ferrors","2.core\u002F6.errors","i-lucide-triangle-alert",{"title":63,"path":64,"stem":65,"icon":66},"Middleware","\u002Fcore\u002Fmiddleware","2.core\u002F7.middleware","i-lucide-layers",{"title":68,"icon":69,"path":70,"stem":71,"children":72,"page":25},"Auth","i-lucide-shield-check","\u002Fauth","3.auth",[73,78,83,88,93],{"title":74,"path":75,"stem":76,"icon":77},"Overview","\u002Fauth\u002Foverview","3.auth\u002F1.overview","i-lucide-shield",{"title":79,"path":80,"stem":81,"icon":82},"Auth Rules","\u002Fauth\u002Fauth-rules","3.auth\u002F2.auth-rules","i-lucide-lock",{"title":84,"path":85,"stem":86,"icon":87},"JWT Providers","\u002Fauth\u002Fjwt-providers","3.auth\u002F3.jwt-providers","i-lucide-key",{"title":89,"path":90,"stem":91,"icon":92},"Roles & Permissions","\u002Fauth\u002Froles-and-permissions","3.auth\u002F4.roles-and-permissions","i-lucide-users",{"title":94,"path":95,"stem":96,"icon":97},"Audit Logging","\u002Fauth\u002Faudit-logging","3.auth\u002F5.audit-logging","i-lucide-scroll-text",{"title":99,"icon":100,"path":101,"stem":102,"children":103,"page":25},"GoTrue","i-lucide-key-round","\u002Fgotrue","4.gotrue",[104,109,114,119],{"title":105,"path":106,"stem":107,"icon":108},"Proxy","\u002Fgotrue\u002Fproxy","4.gotrue\u002F1.proxy","i-lucide-shuffle",{"title":110,"path":111,"stem":112,"icon":113},"Endpoints","\u002Fgotrue\u002Fendpoints","4.gotrue\u002F2.endpoints","i-lucide-list",{"title":115,"path":116,"stem":117,"icon":118},"Client IP & Rate Limits","\u002Fgotrue\u002Fclient-ip-and-rate-limits","4.gotrue\u002F3.client-ip-and-rate-limits","i-lucide-network",{"title":120,"path":121,"stem":122,"icon":123},"Deployment","\u002Fgotrue\u002Fdeployment","4.gotrue\u002F4.deployment","i-lucide-server",{"title":125,"icon":126,"path":127,"stem":128,"children":129,"page":25},"API Docs","i-lucide-file-text","\u002Fapi-docs","5.api-docs",[130,135],{"title":131,"path":132,"stem":133,"icon":134},"OpenAPI","\u002Fapi-docs\u002Fopenapi","5.api-docs\u002F1.openapi","i-lucide-file-json",{"title":136,"path":137,"stem":138,"icon":139},"Scalar UI","\u002Fapi-docs\u002Fscalar","5.api-docs\u002F2.scalar","i-lucide-book-open-text",{"title":141,"icon":142,"path":143,"stem":144,"children":145,"page":25},"Guides","i-lucide-compass","\u002Fguides","6.guides",[146,151,156],{"title":147,"path":148,"stem":149,"icon":150},"Testing","\u002Fguides\u002Ftesting","6.guides\u002F1.testing","i-lucide-flask-conical",{"title":152,"path":153,"stem":154,"icon":155},"Performance","\u002Fguides\u002Fperformance","6.guides\u002F2.performance","i-lucide-gauge",{"title":157,"path":158,"stem":159,"icon":160},"Releasing","\u002Fguides\u002Freleasing","6.guides\u002F3.releasing","i-lucide-tag",{"title":162,"icon":163,"path":164,"stem":165,"children":166,"page":25},"Reference","i-lucide-code","\u002Freference","7.reference",[167],{"title":168,"path":169,"stem":170,"icon":171},"API Reference","\u002Freference\u002Fapi-reference","7.reference\u002F1.api-reference","i-lucide-list-tree",{"id":173,"title":33,"body":174,"description":1915,"extension":1916,"links":1917,"meta":1918,"navigation":1919,"path":34,"seo":1920,"stem":35,"__hash__":1921},"docs\u002F2.core\u002F1.routing.md",{"type":175,"value":176,"toc":1905},"minimark",[177,190,195,206,480,494,602,608,612,623,703,706,746,749,844,848,858,942,945,1067,1078,1087,1091,1094,1235,1241,1340,1348,1352,1357,1479,1579,1585,1589,1743,1753,1757,1767,1883,1887,1901],[178,179,180,181,185,186,189],"p",{},"Routing is Go's ",[182,183,184],"code",{},"net\u002Fhttp.ServeMux",". ezz registers ",[182,187,188],{},"METHOD \u002Fpattern"," entries on a mux it owns, so pattern syntax, precedence, and conflict rules are the standard library's.",[191,192,194],"h2",{"id":193},"register-a-route","Register a route",[178,196,197,198,201,202,205],{},"Each HTTP method has a matching function on the app. They all take a pattern and an ",[182,199,200],{},"http.Handler",", and return a ",[182,203,204],{},"*RouteBuilder"," you can chain metadata onto.",[207,208,213],"pre",{"className":209,"code":210,"language":211,"meta":212,"style":212},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","app := ezz.New()\n\napp.GET(\"\u002Fusers\", listUsers)\napp.POST(\"\u002Fusers\", createUser)\napp.PUT(\"\u002Fusers\u002F{id}\", replaceUser)\napp.PATCH(\"\u002Fusers\u002F{id}\", updateUser)\napp.DELETE(\"\u002Fusers\u002F{id}\", deleteUser)\napp.HEAD(\"\u002Fhealth\", healthHead)\napp.OPTIONS(\"\u002Fusers\", usersOptions)\n\n\u002F\u002F any other method\napp.Handle(\"TRACE\", \"\u002Fdebug\", traceHandler)\n","go","",[182,214,215,241,248,280,305,331,356,381,407,432,437,444],{"__ignoreMap":212},[216,217,220,224,228,231,234,238],"span",{"class":218,"line":219},"line",1,[216,221,223],{"class":222},"sTEyZ","app ",[216,225,227],{"class":226},"sMK4o",":=",[216,229,230],{"class":222}," ezz",[216,232,233],{"class":226},".",[216,235,237],{"class":236},"s2Zo4","New",[216,239,240],{"class":226},"()\n",[216,242,244],{"class":218,"line":243},2,[216,245,247],{"emptyLinePlaceholder":246},true,"\n",[216,249,251,254,256,259,262,265,269,271,274,277],{"class":218,"line":250},3,[216,252,253],{"class":222},"app",[216,255,233],{"class":226},[216,257,258],{"class":236},"GET",[216,260,261],{"class":226},"(",[216,263,264],{"class":226},"\"",[216,266,268],{"class":267},"sfazB","\u002Fusers",[216,270,264],{"class":226},[216,272,273],{"class":226},",",[216,275,276],{"class":222}," listUsers",[216,278,279],{"class":226},")\n",[216,281,283,285,287,290,292,294,296,298,300,303],{"class":218,"line":282},4,[216,284,253],{"class":222},[216,286,233],{"class":226},[216,288,289],{"class":236},"POST",[216,291,261],{"class":226},[216,293,264],{"class":226},[216,295,268],{"class":267},[216,297,264],{"class":226},[216,299,273],{"class":226},[216,301,302],{"class":222}," createUser",[216,304,279],{"class":226},[216,306,308,310,312,315,317,319,322,324,326,329],{"class":218,"line":307},5,[216,309,253],{"class":222},[216,311,233],{"class":226},[216,313,314],{"class":236},"PUT",[216,316,261],{"class":226},[216,318,264],{"class":226},[216,320,321],{"class":267},"\u002Fusers\u002F{id}",[216,323,264],{"class":226},[216,325,273],{"class":226},[216,327,328],{"class":222}," replaceUser",[216,330,279],{"class":226},[216,332,334,336,338,341,343,345,347,349,351,354],{"class":218,"line":333},6,[216,335,253],{"class":222},[216,337,233],{"class":226},[216,339,340],{"class":236},"PATCH",[216,342,261],{"class":226},[216,344,264],{"class":226},[216,346,321],{"class":267},[216,348,264],{"class":226},[216,350,273],{"class":226},[216,352,353],{"class":222}," updateUser",[216,355,279],{"class":226},[216,357,359,361,363,366,368,370,372,374,376,379],{"class":218,"line":358},7,[216,360,253],{"class":222},[216,362,233],{"class":226},[216,364,365],{"class":236},"DELETE",[216,367,261],{"class":226},[216,369,264],{"class":226},[216,371,321],{"class":267},[216,373,264],{"class":226},[216,375,273],{"class":226},[216,377,378],{"class":222}," deleteUser",[216,380,279],{"class":226},[216,382,384,386,388,391,393,395,398,400,402,405],{"class":218,"line":383},8,[216,385,253],{"class":222},[216,387,233],{"class":226},[216,389,390],{"class":236},"HEAD",[216,392,261],{"class":226},[216,394,264],{"class":226},[216,396,397],{"class":267},"\u002Fhealth",[216,399,264],{"class":226},[216,401,273],{"class":226},[216,403,404],{"class":222}," healthHead",[216,406,279],{"class":226},[216,408,410,412,414,417,419,421,423,425,427,430],{"class":218,"line":409},9,[216,411,253],{"class":222},[216,413,233],{"class":226},[216,415,416],{"class":236},"OPTIONS",[216,418,261],{"class":226},[216,420,264],{"class":226},[216,422,268],{"class":267},[216,424,264],{"class":226},[216,426,273],{"class":226},[216,428,429],{"class":222}," usersOptions",[216,431,279],{"class":226},[216,433,435],{"class":218,"line":434},10,[216,436,247],{"emptyLinePlaceholder":246},[216,438,440],{"class":218,"line":439},11,[216,441,443],{"class":442},"sHwdD","\u002F\u002F any other method\n",[216,445,447,449,451,454,456,458,461,463,465,468,471,473,475,478],{"class":218,"line":446},12,[216,448,253],{"class":222},[216,450,233],{"class":226},[216,452,453],{"class":236},"Handle",[216,455,261],{"class":226},[216,457,264],{"class":226},[216,459,460],{"class":267},"TRACE",[216,462,264],{"class":226},[216,464,273],{"class":226},[216,466,467],{"class":226}," \"",[216,469,470],{"class":267},"\u002Fdebug",[216,472,264],{"class":226},[216,474,273],{"class":226},[216,476,477],{"class":222}," traceHandler",[216,479,279],{"class":226},[178,481,482,483,486,487,490,491,493],{},"The handler can be an ",[182,484,485],{},"ezz.H"," typed handler, an ",[182,488,489],{},"http.HandlerFunc",", or anything else implementing ",[182,492,200],{},":",[207,495,497],{"className":209,"code":496,"language":211,"meta":212,"style":212},"app.GET(\"\u002Flegacy\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    w.Write([]byte(\"plain net\u002Fhttp still works\"))\n})).Public()\n",[182,498,499,563,592],{"__ignoreMap":212},[216,500,501,503,505,507,509,511,514,516,518,521,523,526,529,533,536,538,541,543,546,549,552,554,557,560],{"class":218,"line":219},[216,502,253],{"class":222},[216,504,233],{"class":226},[216,506,258],{"class":236},[216,508,261],{"class":226},[216,510,264],{"class":226},[216,512,513],{"class":267},"\u002Flegacy",[216,515,264],{"class":226},[216,517,273],{"class":226},[216,519,520],{"class":222}," http",[216,522,233],{"class":226},[216,524,525],{"class":236},"HandlerFunc",[216,527,528],{"class":226},"(func(",[216,530,532],{"class":531},"sHdIc","w",[216,534,520],{"class":535},"sBMFI",[216,537,233],{"class":226},[216,539,540],{"class":535},"ResponseWriter",[216,542,273],{"class":226},[216,544,545],{"class":531}," r",[216,547,548],{"class":226}," *",[216,550,551],{"class":535},"http",[216,553,233],{"class":226},[216,555,556],{"class":535},"Request",[216,558,559],{"class":226},")",[216,561,562],{"class":226}," {\n",[216,564,565,568,570,573,576,580,582,584,587,589],{"class":218,"line":243},[216,566,567],{"class":222},"    w",[216,569,233],{"class":226},[216,571,572],{"class":236},"Write",[216,574,575],{"class":226},"([]",[216,577,579],{"class":578},"spNyl","byte",[216,581,261],{"class":226},[216,583,264],{"class":226},[216,585,586],{"class":267},"plain net\u002Fhttp still works",[216,588,264],{"class":226},[216,590,591],{"class":226},"))\n",[216,593,594,597,600],{"class":218,"line":250},[216,595,596],{"class":226},"})).",[216,598,599],{"class":236},"Public",[216,601,240],{"class":226},[178,603,604,605,607],{},"Typed handlers additionally expose their request and response types, which is what the OpenAPI generator reads. A plain ",[182,606,200],{}," still routes and still respects auth rules, it just has no schema to document.",[191,609,611],{"id":610},"match-path-parameters","Match path parameters",[178,613,614,615,618,619,622],{},"Patterns use ",[182,616,617],{},"{name}"," for a single segment and ",[182,620,621],{},"{name...}"," for a trailing wildcard.",[207,624,626],{"className":209,"code":625,"language":211,"meta":212,"style":212},"app.GET(\"\u002Fusers\u002F{id}\", handler)             \u002F\u002F \u002Fusers\u002F42\napp.GET(\"\u002Ffiles\u002F{path...}\", handler)        \u002F\u002F \u002Ffiles\u002Fa\u002Fb\u002Fc.txt\napp.GET(\"\u002Forgs\u002F{org}\u002Frepos\u002F{repo}\", handler)\n",[182,627,628,654,680],{"__ignoreMap":212},[216,629,630,632,634,636,638,640,642,644,646,649,651],{"class":218,"line":219},[216,631,253],{"class":222},[216,633,233],{"class":226},[216,635,258],{"class":236},[216,637,261],{"class":226},[216,639,264],{"class":226},[216,641,321],{"class":267},[216,643,264],{"class":226},[216,645,273],{"class":226},[216,647,648],{"class":222}," handler",[216,650,559],{"class":226},[216,652,653],{"class":442},"             \u002F\u002F \u002Fusers\u002F42\n",[216,655,656,658,660,662,664,666,669,671,673,675,677],{"class":218,"line":243},[216,657,253],{"class":222},[216,659,233],{"class":226},[216,661,258],{"class":236},[216,663,261],{"class":226},[216,665,264],{"class":226},[216,667,668],{"class":267},"\u002Ffiles\u002F{path...}",[216,670,264],{"class":226},[216,672,273],{"class":226},[216,674,648],{"class":222},[216,676,559],{"class":226},[216,678,679],{"class":442},"        \u002F\u002F \u002Ffiles\u002Fa\u002Fb\u002Fc.txt\n",[216,681,682,684,686,688,690,692,695,697,699,701],{"class":218,"line":250},[216,683,253],{"class":222},[216,685,233],{"class":226},[216,687,258],{"class":236},[216,689,261],{"class":226},[216,691,264],{"class":226},[216,693,694],{"class":267},"\u002Forgs\u002F{org}\u002Frepos\u002F{repo}",[216,696,264],{"class":226},[216,698,273],{"class":226},[216,700,648],{"class":222},[216,702,279],{"class":226},[178,704,705],{},"Read them through the request type, which is the usual case:",[207,707,709],{"className":209,"code":708,"language":211,"meta":212,"style":212},"type GetUserRequest struct {\n    ID string `path:\"id\" validate:\"required\"`\n}\n",[182,710,711,724,741],{"__ignoreMap":212},[216,712,713,716,719,722],{"class":218,"line":219},[216,714,715],{"class":226},"type",[216,717,718],{"class":535}," GetUserRequest",[216,720,721],{"class":226}," struct",[216,723,562],{"class":226},[216,725,726,729,732,735,738],{"class":218,"line":243},[216,727,728],{"class":222},"    ID ",[216,730,731],{"class":578},"string",[216,733,734],{"class":226}," `",[216,736,737],{"class":267},"path:\"id\" validate:\"required\"",[216,739,740],{"class":226},"`\n",[216,742,743],{"class":218,"line":250},[216,744,745],{"class":226},"}\n",[178,747,748],{},"Or read them from the context when you have no request struct:",[207,750,752],{"className":209,"code":751,"language":211,"meta":212,"style":212},"app.GET(\"\u002Fusers\u002F{id}\", ezz.HFunc(func(ctx *ezz.Context) (*User, error) {\n    return lookup(ctx.Param(\"id\"))\n}))\n",[182,753,754,810,839],{"__ignoreMap":212},[216,755,756,758,760,762,764,766,768,770,772,774,776,779,781,784,786,789,791,793,795,798,801,803,806,808],{"class":218,"line":219},[216,757,253],{"class":222},[216,759,233],{"class":226},[216,761,258],{"class":236},[216,763,261],{"class":226},[216,765,264],{"class":226},[216,767,321],{"class":267},[216,769,264],{"class":226},[216,771,273],{"class":226},[216,773,230],{"class":222},[216,775,233],{"class":226},[216,777,778],{"class":236},"HFunc",[216,780,528],{"class":226},[216,782,783],{"class":531},"ctx",[216,785,548],{"class":226},[216,787,788],{"class":535},"ezz",[216,790,233],{"class":226},[216,792,53],{"class":535},[216,794,559],{"class":226},[216,796,797],{"class":226}," (*",[216,799,800],{"class":535},"User",[216,802,273],{"class":226},[216,804,805],{"class":578}," error",[216,807,559],{"class":226},[216,809,562],{"class":226},[216,811,812,816,819,821,823,825,828,830,832,835,837],{"class":218,"line":243},[216,813,815],{"class":814},"s7zQu","    return",[216,817,818],{"class":236}," lookup",[216,820,261],{"class":226},[216,822,783],{"class":222},[216,824,233],{"class":226},[216,826,827],{"class":236},"Param",[216,829,261],{"class":226},[216,831,264],{"class":226},[216,833,834],{"class":267},"id",[216,836,264],{"class":226},[216,838,591],{"class":226},[216,840,841],{"class":218,"line":250},[216,842,843],{"class":226},"}))\n",[191,845,847],{"id":846},"group-related-routes","Group related routes",[178,849,850,853,854,857],{},[182,851,852],{},"app.Group(prefix)"," returns a ",[182,855,856],{},"*RouteGroup"," that shares a path prefix, and optionally middleware and an auth rule, with every route registered on it.",[207,859,861],{"className":209,"code":860,"language":211,"meta":212,"style":212},"api := app.Group(\"\u002Fapi\u002Fv1\")\n\napi.GET(\"\", listRoot)          \u002F\u002F \u002Fapi\u002Fv1\napi.GET(\"\u002Fusers\", listUsers)   \u002F\u002F \u002Fapi\u002Fv1\u002Fusers\n",[182,862,863,889,893,917],{"__ignoreMap":212},[216,864,865,868,870,873,875,878,880,882,885,887],{"class":218,"line":219},[216,866,867],{"class":222},"api ",[216,869,227],{"class":226},[216,871,872],{"class":222}," app",[216,874,233],{"class":226},[216,876,877],{"class":236},"Group",[216,879,261],{"class":226},[216,881,264],{"class":226},[216,883,884],{"class":267},"\u002Fapi\u002Fv1",[216,886,264],{"class":226},[216,888,279],{"class":226},[216,890,891],{"class":218,"line":243},[216,892,247],{"emptyLinePlaceholder":246},[216,894,895,898,900,902,904,907,909,912,914],{"class":218,"line":250},[216,896,897],{"class":222},"api",[216,899,233],{"class":226},[216,901,258],{"class":236},[216,903,261],{"class":226},[216,905,906],{"class":226},"\"\"",[216,908,273],{"class":226},[216,910,911],{"class":222}," listRoot",[216,913,559],{"class":226},[216,915,916],{"class":442},"          \u002F\u002F \u002Fapi\u002Fv1\n",[216,918,919,921,923,925,927,929,931,933,935,937,939],{"class":218,"line":282},[216,920,897],{"class":222},[216,922,233],{"class":226},[216,924,258],{"class":236},[216,926,261],{"class":226},[216,928,264],{"class":226},[216,930,268],{"class":267},[216,932,264],{"class":226},[216,934,273],{"class":226},[216,936,276],{"class":222},[216,938,559],{"class":226},[216,940,941],{"class":442},"   \u002F\u002F \u002Fapi\u002Fv1\u002Fusers\n",[178,943,944],{},"Groups nest, and a child copies the parent's middleware and auth rule at the moment it is created:",[207,946,948],{"className":209,"code":947,"language":211,"meta":212,"style":212},"api := app.Group(\"\u002Fapi\u002Fv1\").Use(middleware.Gzip())\nadmin := api.Group(\"\u002Fadmin\").Auth(ezz.Role(\"admin\"))\n\nadmin.GET(\"\u002Fstats\", stats)   \u002F\u002F \u002Fapi\u002Fv1\u002Fadmin\u002Fstats, gzipped, admin only\n",[182,949,950,989,1036,1040],{"__ignoreMap":212},[216,951,952,954,956,958,960,962,964,966,968,970,973,976,978,981,983,986],{"class":218,"line":219},[216,953,867],{"class":222},[216,955,227],{"class":226},[216,957,872],{"class":222},[216,959,233],{"class":226},[216,961,877],{"class":236},[216,963,261],{"class":226},[216,965,264],{"class":226},[216,967,884],{"class":267},[216,969,264],{"class":226},[216,971,972],{"class":226},").",[216,974,975],{"class":236},"Use",[216,977,261],{"class":226},[216,979,980],{"class":222},"middleware",[216,982,233],{"class":226},[216,984,985],{"class":236},"Gzip",[216,987,988],{"class":226},"())\n",[216,990,991,994,996,999,1001,1003,1005,1007,1010,1012,1014,1016,1018,1020,1022,1025,1027,1029,1032,1034],{"class":218,"line":243},[216,992,993],{"class":222},"admin ",[216,995,227],{"class":226},[216,997,998],{"class":222}," api",[216,1000,233],{"class":226},[216,1002,877],{"class":236},[216,1004,261],{"class":226},[216,1006,264],{"class":226},[216,1008,1009],{"class":267},"\u002Fadmin",[216,1011,264],{"class":226},[216,1013,972],{"class":226},[216,1015,68],{"class":236},[216,1017,261],{"class":226},[216,1019,788],{"class":222},[216,1021,233],{"class":226},[216,1023,1024],{"class":236},"Role",[216,1026,261],{"class":226},[216,1028,264],{"class":226},[216,1030,1031],{"class":267},"admin",[216,1033,264],{"class":226},[216,1035,591],{"class":226},[216,1037,1038],{"class":218,"line":250},[216,1039,247],{"emptyLinePlaceholder":246},[216,1041,1042,1044,1046,1048,1050,1052,1055,1057,1059,1062,1064],{"class":218,"line":282},[216,1043,1031],{"class":222},[216,1045,233],{"class":226},[216,1047,258],{"class":236},[216,1049,261],{"class":226},[216,1051,264],{"class":226},[216,1053,1054],{"class":267},"\u002Fstats",[216,1056,264],{"class":226},[216,1058,273],{"class":226},[216,1060,1061],{"class":222}," stats",[216,1063,559],{"class":226},[216,1065,1066],{"class":442},"   \u002F\u002F \u002Fapi\u002Fv1\u002Fadmin\u002Fstats, gzipped, admin only\n",[178,1068,1069,1070,1073,1074,1077],{},"Trailing slashes on the prefix are trimmed, so ",[182,1071,1072],{},"Group(\"\u002Fapi\u002F\")"," and ",[182,1075,1076],{},"Group(\"\u002Fapi\")"," behave the same.",[1079,1080,1081,1082,1073,1084,1086],"warning",{},"A group snapshots its middleware and auth rule when a route is registered, and a child group snapshots the parent when the child is created. Call ",[182,1083,975],{},[182,1085,68],{}," on a group before registering routes on it or creating children from it.",[191,1088,1090],{"id":1089},"override-auth-per-route","Override auth per route",[178,1092,1093],{},"Precedence runs from broad to narrow: the app default, then the group rule, then the route rule.",[207,1095,1097],{"className":209,"code":1096,"language":211,"meta":212,"style":212},"app := ezz.New().Auth(provider)      \u002F\u002F default: any valid token\n\napp.GET(\"\u002Fhealth\", health).Public()               \u002F\u002F no auth\napp.GET(\"\u002Fadmin\", panel).Auth(ezz.Role(\"admin\"))  \u002F\u002F admin only\napp.GET(\"\u002Fme\", profile)                            \u002F\u002F inherits the default\n",[182,1098,1099,1126,1130,1161,1208],{"__ignoreMap":212},[216,1100,1101,1103,1105,1107,1109,1111,1114,1116,1118,1121,1123],{"class":218,"line":219},[216,1102,223],{"class":222},[216,1104,227],{"class":226},[216,1106,230],{"class":222},[216,1108,233],{"class":226},[216,1110,237],{"class":236},[216,1112,1113],{"class":226},"().",[216,1115,68],{"class":236},[216,1117,261],{"class":226},[216,1119,1120],{"class":222},"provider",[216,1122,559],{"class":226},[216,1124,1125],{"class":442},"      \u002F\u002F default: any valid token\n",[216,1127,1128],{"class":218,"line":243},[216,1129,247],{"emptyLinePlaceholder":246},[216,1131,1132,1134,1136,1138,1140,1142,1144,1146,1148,1151,1153,1155,1158],{"class":218,"line":250},[216,1133,253],{"class":222},[216,1135,233],{"class":226},[216,1137,258],{"class":236},[216,1139,261],{"class":226},[216,1141,264],{"class":226},[216,1143,397],{"class":267},[216,1145,264],{"class":226},[216,1147,273],{"class":226},[216,1149,1150],{"class":222}," health",[216,1152,972],{"class":226},[216,1154,599],{"class":236},[216,1156,1157],{"class":226},"()",[216,1159,1160],{"class":442},"               \u002F\u002F no auth\n",[216,1162,1163,1165,1167,1169,1171,1173,1175,1177,1179,1182,1184,1186,1188,1190,1192,1194,1196,1198,1200,1202,1205],{"class":218,"line":282},[216,1164,253],{"class":222},[216,1166,233],{"class":226},[216,1168,258],{"class":236},[216,1170,261],{"class":226},[216,1172,264],{"class":226},[216,1174,1009],{"class":267},[216,1176,264],{"class":226},[216,1178,273],{"class":226},[216,1180,1181],{"class":222}," panel",[216,1183,972],{"class":226},[216,1185,68],{"class":236},[216,1187,261],{"class":226},[216,1189,788],{"class":222},[216,1191,233],{"class":226},[216,1193,1024],{"class":236},[216,1195,261],{"class":226},[216,1197,264],{"class":226},[216,1199,1031],{"class":267},[216,1201,264],{"class":226},[216,1203,1204],{"class":226},"))",[216,1206,1207],{"class":442},"  \u002F\u002F admin only\n",[216,1209,1210,1212,1214,1216,1218,1220,1223,1225,1227,1230,1232],{"class":218,"line":307},[216,1211,253],{"class":222},[216,1213,233],{"class":226},[216,1215,258],{"class":236},[216,1217,261],{"class":226},[216,1219,264],{"class":226},[216,1221,1222],{"class":267},"\u002Fme",[216,1224,264],{"class":226},[216,1226,273],{"class":226},[216,1228,1229],{"class":222}," profile",[216,1231,559],{"class":226},[216,1233,1234],{"class":442},"                            \u002F\u002F inherits the default\n",[178,1236,1237,1238,493],{},"To make routes public by default and opt into auth instead, pass ",[182,1239,1240],{},"nil",[207,1242,1244],{"className":209,"code":1243,"language":211,"meta":212,"style":212},"app := ezz.New().Auth(provider).DefaultAuth(nil)\n\napp.GET(\"\u002Fopen\", handler)                          \u002F\u002F public\napp.GET(\"\u002Fclosed\", handler).Auth(ezz.Authenticated())\n",[182,1245,1246,1274,1278,1304],{"__ignoreMap":212},[216,1247,1248,1250,1252,1254,1256,1258,1260,1262,1264,1266,1268,1271],{"class":218,"line":219},[216,1249,223],{"class":222},[216,1251,227],{"class":226},[216,1253,230],{"class":222},[216,1255,233],{"class":226},[216,1257,237],{"class":236},[216,1259,1113],{"class":226},[216,1261,68],{"class":236},[216,1263,261],{"class":226},[216,1265,1120],{"class":222},[216,1267,972],{"class":226},[216,1269,1270],{"class":236},"DefaultAuth",[216,1272,1273],{"class":226},"(nil)\n",[216,1275,1276],{"class":218,"line":243},[216,1277,247],{"emptyLinePlaceholder":246},[216,1279,1280,1282,1284,1286,1288,1290,1293,1295,1297,1299,1301],{"class":218,"line":250},[216,1281,253],{"class":222},[216,1283,233],{"class":226},[216,1285,258],{"class":236},[216,1287,261],{"class":226},[216,1289,264],{"class":226},[216,1291,1292],{"class":267},"\u002Fopen",[216,1294,264],{"class":226},[216,1296,273],{"class":226},[216,1298,648],{"class":222},[216,1300,559],{"class":226},[216,1302,1303],{"class":442},"                          \u002F\u002F public\n",[216,1305,1306,1308,1310,1312,1314,1316,1319,1321,1323,1325,1327,1329,1331,1333,1335,1338],{"class":218,"line":282},[216,1307,253],{"class":222},[216,1309,233],{"class":226},[216,1311,258],{"class":236},[216,1313,261],{"class":226},[216,1315,264],{"class":226},[216,1317,1318],{"class":267},"\u002Fclosed",[216,1320,264],{"class":226},[216,1322,273],{"class":226},[216,1324,648],{"class":222},[216,1326,972],{"class":226},[216,1328,68],{"class":236},[216,1330,261],{"class":226},[216,1332,788],{"class":222},[216,1334,233],{"class":226},[216,1336,1337],{"class":236},"Authenticated",[216,1339,988],{"class":226},[178,1341,1342,1343,1347],{},"See ",[1344,1345,1346],"a",{"href":80},"Auth rules"," for the full set of rules.",[191,1349,1351],{"id":1350},"attach-metadata-for-the-docs","Attach metadata for the docs",[178,1353,1354,1355,493],{},"Every registration returns a ",[182,1356,204],{},[207,1358,1360],{"className":209,"code":1359,"language":211,"meta":212,"style":212},"app.GET(\"\u002Fusers\u002F{id}\", getUser).\n    Tags(\"Users\").\n    Description(\"Returns a single user by ID.\").\n    Summary(\"Get user\").\n    OperationID(\"getUser\").\n    Response(404, \"User not found\").\n    Deprecated()\n",[182,1361,1362,1386,1402,1418,1434,1450,1472],{"__ignoreMap":212},[216,1363,1364,1366,1368,1370,1372,1374,1376,1378,1380,1383],{"class":218,"line":219},[216,1365,253],{"class":222},[216,1367,233],{"class":226},[216,1369,258],{"class":236},[216,1371,261],{"class":226},[216,1373,264],{"class":226},[216,1375,321],{"class":267},[216,1377,264],{"class":226},[216,1379,273],{"class":226},[216,1381,1382],{"class":222}," getUser",[216,1384,1385],{"class":226},").\n",[216,1387,1388,1391,1393,1395,1398,1400],{"class":218,"line":243},[216,1389,1390],{"class":236},"    Tags",[216,1392,261],{"class":226},[216,1394,264],{"class":226},[216,1396,1397],{"class":267},"Users",[216,1399,264],{"class":226},[216,1401,1385],{"class":226},[216,1403,1404,1407,1409,1411,1414,1416],{"class":218,"line":250},[216,1405,1406],{"class":236},"    Description",[216,1408,261],{"class":226},[216,1410,264],{"class":226},[216,1412,1413],{"class":267},"Returns a single user by ID.",[216,1415,264],{"class":226},[216,1417,1385],{"class":226},[216,1419,1420,1423,1425,1427,1430,1432],{"class":218,"line":282},[216,1421,1422],{"class":236},"    Summary",[216,1424,261],{"class":226},[216,1426,264],{"class":226},[216,1428,1429],{"class":267},"Get user",[216,1431,264],{"class":226},[216,1433,1385],{"class":226},[216,1435,1436,1439,1441,1443,1446,1448],{"class":218,"line":307},[216,1437,1438],{"class":236},"    OperationID",[216,1440,261],{"class":226},[216,1442,264],{"class":226},[216,1444,1445],{"class":267},"getUser",[216,1447,264],{"class":226},[216,1449,1385],{"class":226},[216,1451,1452,1455,1457,1461,1463,1465,1468,1470],{"class":218,"line":333},[216,1453,1454],{"class":236},"    Response",[216,1456,261],{"class":226},[216,1458,1460],{"class":1459},"sbssI","404",[216,1462,273],{"class":226},[216,1464,467],{"class":226},[216,1466,1467],{"class":267},"User not found",[216,1469,264],{"class":226},[216,1471,1385],{"class":226},[216,1473,1474,1477],{"class":218,"line":358},[216,1475,1476],{"class":236},"    Deprecated",[216,1478,240],{"class":226},[1480,1481,1482,1495],"table",{},[1483,1484,1485],"thead",{},[1486,1487,1488,1492],"tr",{},[1489,1490,1491],"th",{},"Method",[1489,1493,1494],{},"Effect",[1496,1497,1498,1509,1522,1532,1542,1552,1561,1570],"tbody",{},[1486,1499,1500,1506],{},[1501,1502,1503],"td",{},[182,1504,1505],{},"Auth(rule)",[1501,1507,1508],{},"Sets the auth rule for this route",[1486,1510,1511,1516],{},[1501,1512,1513],{},[182,1514,1515],{},"Public()",[1501,1517,1518,1519],{},"Shorthand for ",[182,1520,1521],{},"Auth(ezz.Public())",[1486,1523,1524,1529],{},[1501,1525,1526],{},[182,1527,1528],{},"Tags(...)",[1501,1530,1531],{},"OpenAPI tags, also used to group operations in the docs UI",[1486,1533,1534,1539],{},[1501,1535,1536],{},[182,1537,1538],{},"Description(text)",[1501,1540,1541],{},"OpenAPI operation description",[1486,1543,1544,1549],{},[1501,1545,1546],{},[182,1547,1548],{},"Summary(text)",[1501,1550,1551],{},"Stored on the route",[1486,1553,1554,1559],{},[1501,1555,1556],{},[182,1557,1558],{},"OperationID(id)",[1501,1560,1551],{},[1486,1562,1563,1568],{},[1501,1564,1565],{},[182,1566,1567],{},"Deprecated()",[1501,1569,1551],{},[1486,1571,1572,1577],{},[1501,1573,1574],{},[182,1575,1576],{},"Response(status, description, example...)",[1501,1578,1551],{},[1580,1581,1582,1583,233],"note",{},"Tags and description are the two fields the current OpenAPI generator emits. Summary, operation ID, deprecation, and extra responses are recorded on the route but not yet written into the spec; operation IDs are generated from the method and path instead. See ",[1344,1584,131],{"href":132},[191,1586,1588],{"id":1587},"start-serving","Start serving",[207,1590,1592],{"className":209,"code":1591,"language":211,"meta":212,"style":212},"\u002F\u002F the convenience path\nlog.Fatal(app.Listen(\":8080\"))\n\n\u002F\u002F or drive the server yourself, since App is an http.Handler\nsrv := &http.Server{\n    Addr:              \":8080\",\n    Handler:           app,\n    ReadHeaderTimeout: 5 * time.Second,\n}\nlog.Fatal(srv.ListenAndServeTLS(certFile, keyFile))\n",[182,1593,1594,1599,1629,1633,1638,1658,1675,1687,1709,1713],{"__ignoreMap":212},[216,1595,1596],{"class":218,"line":219},[216,1597,1598],{"class":442},"\u002F\u002F the convenience path\n",[216,1600,1601,1604,1606,1609,1611,1613,1615,1618,1620,1622,1625,1627],{"class":218,"line":243},[216,1602,1603],{"class":222},"log",[216,1605,233],{"class":226},[216,1607,1608],{"class":236},"Fatal",[216,1610,261],{"class":226},[216,1612,253],{"class":222},[216,1614,233],{"class":226},[216,1616,1617],{"class":236},"Listen",[216,1619,261],{"class":226},[216,1621,264],{"class":226},[216,1623,1624],{"class":267},":8080",[216,1626,264],{"class":226},[216,1628,591],{"class":226},[216,1630,1631],{"class":218,"line":250},[216,1632,247],{"emptyLinePlaceholder":246},[216,1634,1635],{"class":218,"line":282},[216,1636,1637],{"class":442},"\u002F\u002F or drive the server yourself, since App is an http.Handler\n",[216,1639,1640,1643,1645,1648,1650,1652,1655],{"class":218,"line":307},[216,1641,1642],{"class":222},"srv ",[216,1644,227],{"class":226},[216,1646,1647],{"class":226}," &",[216,1649,551],{"class":535},[216,1651,233],{"class":226},[216,1653,1654],{"class":535},"Server",[216,1656,1657],{"class":226},"{\n",[216,1659,1660,1663,1665,1668,1670,1672],{"class":218,"line":333},[216,1661,1662],{"class":222},"    Addr",[216,1664,493],{"class":226},[216,1666,1667],{"class":226},"              \"",[216,1669,1624],{"class":267},[216,1671,264],{"class":226},[216,1673,1674],{"class":226},",\n",[216,1676,1677,1680,1682,1685],{"class":218,"line":358},[216,1678,1679],{"class":222},"    Handler",[216,1681,493],{"class":226},[216,1683,1684],{"class":222},"           app",[216,1686,1674],{"class":226},[216,1688,1689,1692,1694,1697,1699,1702,1704,1707],{"class":218,"line":383},[216,1690,1691],{"class":222},"    ReadHeaderTimeout",[216,1693,493],{"class":226},[216,1695,1696],{"class":1459}," 5",[216,1698,548],{"class":226},[216,1700,1701],{"class":222}," time",[216,1703,233],{"class":226},[216,1705,1706],{"class":222},"Second",[216,1708,1674],{"class":226},[216,1710,1711],{"class":218,"line":409},[216,1712,745],{"class":226},[216,1714,1715,1717,1719,1721,1723,1726,1728,1731,1733,1736,1738,1741],{"class":218,"line":434},[216,1716,1603],{"class":222},[216,1718,233],{"class":226},[216,1720,1608],{"class":236},[216,1722,261],{"class":226},[216,1724,1725],{"class":222},"srv",[216,1727,233],{"class":226},[216,1729,1730],{"class":236},"ListenAndServeTLS",[216,1732,261],{"class":226},[216,1734,1735],{"class":222},"certFile",[216,1737,273],{"class":226},[216,1739,1740],{"class":222}," keyFile",[216,1742,591],{"class":226},[178,1744,1745,1746,1748,1749,1752],{},"Use the second form when you need timeouts, TLS configuration, or graceful shutdown. ",[182,1747,1617],{}," calls ",[182,1750,1751],{},"http.ListenAndServe"," with no timeouts set.",[191,1754,1756],{"id":1755},"inspect-registered-routes","Inspect registered routes",[178,1758,1759,1762,1763,1766],{},[182,1760,1761],{},"app.Routes()"," returns the ",[182,1764,1765],{},"*ezz.Route"," values, which is what the OpenAPI generator walks. It is also handy for a startup log or a route table in tests.",[207,1768,1770],{"className":209,"code":1769,"language":211,"meta":212,"style":212},"for _, r := range app.Routes() {\n    log.Printf(\"%-6s %-30s public=%t\", r.Method, r.Pattern, r.AuthRule == nil || r.AuthRule.IsPublic())\n}\n",[182,1771,1772,1801,1879],{"__ignoreMap":212},[216,1773,1774,1777,1780,1782,1785,1787,1790,1792,1794,1797,1799],{"class":218,"line":219},[216,1775,1776],{"class":814},"for",[216,1778,1779],{"class":222}," _",[216,1781,273],{"class":226},[216,1783,1784],{"class":222}," r ",[216,1786,227],{"class":226},[216,1788,1789],{"class":814}," range",[216,1791,872],{"class":222},[216,1793,233],{"class":226},[216,1795,1796],{"class":236},"Routes",[216,1798,1157],{"class":226},[216,1800,562],{"class":226},[216,1802,1803,1806,1808,1811,1813,1815,1819,1822,1825,1828,1830,1832,1834,1836,1838,1840,1842,1844,1847,1849,1851,1853,1856,1859,1862,1865,1867,1869,1872,1874,1877],{"class":218,"line":243},[216,1804,1805],{"class":222},"    log",[216,1807,233],{"class":226},[216,1809,1810],{"class":236},"Printf",[216,1812,261],{"class":226},[216,1814,264],{"class":226},[216,1816,1818],{"class":1817},"swJcz","%-6s",[216,1820,1821],{"class":1817}," %-30s",[216,1823,1824],{"class":267}," public=",[216,1826,1827],{"class":1817},"%t",[216,1829,264],{"class":226},[216,1831,273],{"class":226},[216,1833,545],{"class":222},[216,1835,233],{"class":226},[216,1837,1491],{"class":222},[216,1839,273],{"class":226},[216,1841,545],{"class":222},[216,1843,233],{"class":226},[216,1845,1846],{"class":222},"Pattern",[216,1848,273],{"class":226},[216,1850,545],{"class":222},[216,1852,233],{"class":226},[216,1854,1855],{"class":222},"AuthRule ",[216,1857,1858],{"class":226},"==",[216,1860,1861],{"class":226}," nil",[216,1863,1864],{"class":226}," ||",[216,1866,545],{"class":222},[216,1868,233],{"class":226},[216,1870,1871],{"class":222},"AuthRule",[216,1873,233],{"class":226},[216,1875,1876],{"class":236},"IsPublic",[216,1878,988],{"class":226},[216,1880,1881],{"class":218,"line":250},[216,1882,745],{"class":226},[191,1884,1886],{"id":1885},"next-steps","Next steps",[1888,1889,1890,1896],"ul",{},[1891,1892,1893,1895],"li",{},[1344,1894,38],{"href":39}," for what happens inside a route.",[1891,1897,1898,1900],{},[1344,1899,63],{"href":64}," for the wrapping order and the built-in set.",[1902,1903,1904],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .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 .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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .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":212,"searchDepth":243,"depth":243,"links":1906},[1907,1908,1909,1910,1911,1912,1913,1914],{"id":193,"depth":243,"text":194},{"id":610,"depth":243,"text":611},{"id":846,"depth":243,"text":847},{"id":1089,"depth":243,"text":1090},{"id":1350,"depth":243,"text":1351},{"id":1587,"depth":243,"text":1588},{"id":1755,"depth":243,"text":1756},{"id":1885,"depth":243,"text":1886},"Register routes, use path patterns, group them, and attach metadata.","md",null,{},{"icon":36},{"title":33,"description":1915},"zwngqVOs3r2HYXauKxCe1zpbxtuMcF5dx9ngmGkz-0g",[1923,1925],{"title":21,"path":22,"stem":23,"description":1924,"icon":24,"children":-1},"Build an authenticated JSON API with generated OpenAPI docs in one file.",{"title":38,"path":39,"stem":40,"description":1926,"icon":41,"children":-1},"Write typed handlers with ezz.H and ezz.HFunc, and control how responses are written.",1784970047281]