[{"data":1,"prerenderedAt":2135},["ShallowReactive",2],{"navigation_docs":3,"-getting-started-quick-start":172,"-getting-started-quick-start-surround":2130},[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":21,"body":174,"description":2123,"extension":2124,"links":2125,"meta":2126,"navigation":2127,"path":22,"seo":2128,"stem":23,"__hash__":2129},"docs\u002F1.getting-started\u002F3.quick-start.md",{"type":175,"value":176,"toc":2113},"minimark",[177,181,1771,1775,1943,1950,2014,2036,2040,2109],[178,179,180],"p",{},"This walks through a small user API with a login endpoint, protected routes, an admin-only route, and interactive documentation. Everything fits in one file.",[182,183,185,190,200,471,475,478,693,697,703,1118,1122,1125,1426,1430,1448,1674,1678,1689],"steps",{"level":184},"2",[186,187,189],"h2",{"id":188},"create-the-app","Create the app",[178,191,192,196,197,199],{},[193,194,195],"code",{},"ezz.New()"," returns an app with recovery, request ID, and request logging middleware already installed. ",[193,198,68],{}," registers the provider that turns an incoming request into a user, and after that every route requires a valid token until you say otherwise.",[201,202,208],"pre",{"className":203,"code":204,"filename":205,"language":206,"meta":207,"style":207},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package main\n\nimport (\n    \"log\"\n    \"time\"\n\n    \"github.com\u002Fsulv-io\u002Fezz\"\n    \"github.com\u002Fsulv-io\u002Fezz\u002Fauth\"\n    \"github.com\u002Fsulv-io\u002Fezz\u002Fopenapi\"\n)\n\nvar jwt = auth.NewHMACProvider(\"dev-secret-change-me\", \"quickstart\")\n\nfunc main() {\n    app := ezz.New().Auth(auth.NewJWTAuthProvider(jwt))\n\n    \u002F\u002F routes go here\n\n    log.Fatal(app.Listen(\":8080\"))\n}\n","main.go","go","",[193,209,210,223,230,240,252,262,267,277,287,297,303,308,356,361,376,416,421,428,433,465],{"__ignoreMap":207},[211,212,215,219],"span",{"class":213,"line":214},"line",1,[211,216,218],{"class":217},"sMK4o","package",[211,220,222],{"class":221},"sBMFI"," main\n",[211,224,226],{"class":213,"line":225},2,[211,227,229],{"emptyLinePlaceholder":228},true,"\n",[211,231,233,237],{"class":213,"line":232},3,[211,234,236],{"class":235},"s7zQu","import",[211,238,239],{"class":217}," (\n",[211,241,243,246,249],{"class":213,"line":242},4,[211,244,245],{"class":217},"    \"",[211,247,248],{"class":221},"log",[211,250,251],{"class":217},"\"\n",[211,253,255,257,260],{"class":213,"line":254},5,[211,256,245],{"class":217},[211,258,259],{"class":221},"time",[211,261,251],{"class":217},[211,263,265],{"class":213,"line":264},6,[211,266,229],{"emptyLinePlaceholder":228},[211,268,270,272,275],{"class":213,"line":269},7,[211,271,245],{"class":217},[211,273,274],{"class":221},"github.com\u002Fsulv-io\u002Fezz",[211,276,251],{"class":217},[211,278,280,282,285],{"class":213,"line":279},8,[211,281,245],{"class":217},[211,283,284],{"class":221},"github.com\u002Fsulv-io\u002Fezz\u002Fauth",[211,286,251],{"class":217},[211,288,290,292,295],{"class":213,"line":289},9,[211,291,245],{"class":217},[211,293,294],{"class":221},"github.com\u002Fsulv-io\u002Fezz\u002Fopenapi",[211,296,251],{"class":217},[211,298,300],{"class":213,"line":299},10,[211,301,302],{"class":217},")\n",[211,304,306],{"class":213,"line":305},11,[211,307,229],{"emptyLinePlaceholder":228},[211,309,311,314,318,321,324,327,331,334,337,341,343,346,349,352,354],{"class":213,"line":310},12,[211,312,313],{"class":217},"var",[211,315,317],{"class":316},"sTEyZ"," jwt ",[211,319,320],{"class":217},"=",[211,322,323],{"class":316}," auth",[211,325,326],{"class":217},".",[211,328,330],{"class":329},"s2Zo4","NewHMACProvider",[211,332,333],{"class":217},"(",[211,335,336],{"class":217},"\"",[211,338,340],{"class":339},"sfazB","dev-secret-change-me",[211,342,336],{"class":217},[211,344,345],{"class":217},",",[211,347,348],{"class":217}," \"",[211,350,351],{"class":339},"quickstart",[211,353,336],{"class":217},[211,355,302],{"class":217},[211,357,359],{"class":213,"line":358},13,[211,360,229],{"emptyLinePlaceholder":228},[211,362,364,367,370,373],{"class":213,"line":363},14,[211,365,366],{"class":217},"func",[211,368,369],{"class":329}," main",[211,371,372],{"class":217},"()",[211,374,375],{"class":217}," {\n",[211,377,379,382,385,388,390,393,396,398,400,403,405,408,410,413],{"class":213,"line":378},15,[211,380,381],{"class":316},"    app ",[211,383,384],{"class":217},":=",[211,386,387],{"class":316}," ezz",[211,389,326],{"class":217},[211,391,392],{"class":329},"New",[211,394,395],{"class":217},"().",[211,397,68],{"class":329},[211,399,333],{"class":217},[211,401,402],{"class":316},"auth",[211,404,326],{"class":217},[211,406,407],{"class":329},"NewJWTAuthProvider",[211,409,333],{"class":217},[211,411,412],{"class":316},"jwt",[211,414,415],{"class":217},"))\n",[211,417,419],{"class":213,"line":418},16,[211,420,229],{"emptyLinePlaceholder":228},[211,422,424],{"class":213,"line":423},17,[211,425,427],{"class":426},"sHwdD","    \u002F\u002F routes go here\n",[211,429,431],{"class":213,"line":430},18,[211,432,229],{"emptyLinePlaceholder":228},[211,434,436,439,441,444,446,449,451,454,456,458,461,463],{"class":213,"line":435},19,[211,437,438],{"class":316},"    log",[211,440,326],{"class":217},[211,442,443],{"class":329},"Fatal",[211,445,333],{"class":217},[211,447,448],{"class":316},"app",[211,450,326],{"class":217},[211,452,453],{"class":329},"Listen",[211,455,333],{"class":217},[211,457,336],{"class":217},[211,459,460],{"class":339},":8080",[211,462,336],{"class":217},[211,464,415],{"class":217},[211,466,468],{"class":213,"line":467},20,[211,469,470],{"class":217},"}\n",[186,472,474],{"id":473},"describe-your-requests-and-responses","Describe your requests and responses",[178,476,477],{},"Request types carry the binding rules in their tags. Response types are plain structs; ezz serializes whatever you return.",[201,479,481],{"className":203,"code":480,"filename":205,"language":206,"meta":207,"style":207},"type LoginRequest struct {\n    Email    string `json:\"email\" validate:\"required,email\"`\n    Password string `json:\"password\" validate:\"required,min=8\"`\n}\n\ntype LoginResponse struct {\n    Token     string    `json:\"token\"`\n    ExpiresAt time.Time `json:\"expires_at\"`\n}\n\ntype GetUserRequest struct {\n    ID string `path:\"id\" validate:\"required\" description:\"User ID\"`\n}\n\ntype User struct {\n    ID    string `json:\"id\"`\n    Name  string `json:\"name\"`\n    Email string `json:\"email\"`\n    Role  string `json:\"role\"`\n}\n",[193,482,483,496,514,528,532,536,547,562,581,585,589,600,614,618,622,633,647,661,675,689],{"__ignoreMap":207},[211,484,485,488,491,494],{"class":213,"line":214},[211,486,487],{"class":217},"type",[211,489,490],{"class":221}," LoginRequest",[211,492,493],{"class":217}," struct",[211,495,375],{"class":217},[211,497,498,501,505,508,511],{"class":213,"line":225},[211,499,500],{"class":316},"    Email    ",[211,502,504],{"class":503},"spNyl","string",[211,506,507],{"class":217}," `",[211,509,510],{"class":339},"json:\"email\" validate:\"required,email\"",[211,512,513],{"class":217},"`\n",[211,515,516,519,521,523,526],{"class":213,"line":232},[211,517,518],{"class":316},"    Password ",[211,520,504],{"class":503},[211,522,507],{"class":217},[211,524,525],{"class":339},"json:\"password\" validate:\"required,min=8\"",[211,527,513],{"class":217},[211,529,530],{"class":213,"line":242},[211,531,470],{"class":217},[211,533,534],{"class":213,"line":254},[211,535,229],{"emptyLinePlaceholder":228},[211,537,538,540,543,545],{"class":213,"line":264},[211,539,487],{"class":217},[211,541,542],{"class":221}," LoginResponse",[211,544,493],{"class":217},[211,546,375],{"class":217},[211,548,549,552,554,557,560],{"class":213,"line":269},[211,550,551],{"class":316},"    Token     ",[211,553,504],{"class":503},[211,555,556],{"class":217},"    `",[211,558,559],{"class":339},"json:\"token\"",[211,561,513],{"class":217},[211,563,564,567,569,571,574,576,579],{"class":213,"line":279},[211,565,566],{"class":316},"    ExpiresAt ",[211,568,259],{"class":221},[211,570,326],{"class":217},[211,572,573],{"class":221},"Time",[211,575,507],{"class":217},[211,577,578],{"class":339},"json:\"expires_at\"",[211,580,513],{"class":217},[211,582,583],{"class":213,"line":289},[211,584,470],{"class":217},[211,586,587],{"class":213,"line":299},[211,588,229],{"emptyLinePlaceholder":228},[211,590,591,593,596,598],{"class":213,"line":305},[211,592,487],{"class":217},[211,594,595],{"class":221}," GetUserRequest",[211,597,493],{"class":217},[211,599,375],{"class":217},[211,601,602,605,607,609,612],{"class":213,"line":310},[211,603,604],{"class":316},"    ID ",[211,606,504],{"class":503},[211,608,507],{"class":217},[211,610,611],{"class":339},"path:\"id\" validate:\"required\" description:\"User ID\"",[211,613,513],{"class":217},[211,615,616],{"class":213,"line":358},[211,617,470],{"class":217},[211,619,620],{"class":213,"line":363},[211,621,229],{"emptyLinePlaceholder":228},[211,623,624,626,629,631],{"class":213,"line":378},[211,625,487],{"class":217},[211,627,628],{"class":221}," User",[211,630,493],{"class":217},[211,632,375],{"class":217},[211,634,635,638,640,642,645],{"class":213,"line":418},[211,636,637],{"class":316},"    ID    ",[211,639,504],{"class":503},[211,641,507],{"class":217},[211,643,644],{"class":339},"json:\"id\"",[211,646,513],{"class":217},[211,648,649,652,654,656,659],{"class":213,"line":423},[211,650,651],{"class":316},"    Name  ",[211,653,504],{"class":503},[211,655,507],{"class":217},[211,657,658],{"class":339},"json:\"name\"",[211,660,513],{"class":217},[211,662,663,666,668,670,673],{"class":213,"line":430},[211,664,665],{"class":316},"    Email ",[211,667,504],{"class":503},[211,669,507],{"class":217},[211,671,672],{"class":339},"json:\"email\"",[211,674,513],{"class":217},[211,676,677,680,682,684,687],{"class":213,"line":435},[211,678,679],{"class":316},"    Role  ",[211,681,504],{"class":503},[211,683,507],{"class":217},[211,685,686],{"class":339},"json:\"role\"",[211,688,513],{"class":217},[211,690,691],{"class":213,"line":467},[211,692,470],{"class":217},[186,694,696],{"id":695},"add-a-public-login-route","Add a public login route",[178,698,699,702],{},[193,700,701],{},".Public()"," opts a route out of authentication, which you need for login. Roles you want to check later go into the token's custom claims.",[201,704,706],{"className":203,"code":705,"filename":205,"language":206,"meta":207,"style":207},"app.POST(\"\u002Flogin\", ezz.H(func(ctx *ezz.Context, req LoginRequest) (*LoginResponse, error) {\n    user, ok := authenticate(req.Email, req.Password)\n    if !ok {\n        return nil, ezz.Unauthorized(\"invalid email or password\")\n    }\n\n    expires := time.Now().Add(24 * time.Hour)\n    token, err := jwt.GenerateToken(&auth.Claims{\n        Subject:   user.ID,\n        ExpiresAt: expires.Unix(),\n        Custom:    map[string]any{\"role\": user.Role},\n    })\n    if err != nil {\n        return nil, ezz.InternalServerError(\"could not issue token\")\n    }\n\n    return &LoginResponse{Token: token, ExpiresAt: expires}, nil\n})).Public().Tags(\"Auth\")\n",[193,707,708,777,813,827,853,858,862,899,931,950,968,1009,1014,1028,1052,1056,1060,1095],{"__ignoreMap":207},[211,709,710,712,714,717,719,721,724,726,728,730,732,735,738,742,745,748,750,752,754,757,759,762,765,768,770,773,775],{"class":213,"line":214},[211,711,448],{"class":316},[211,713,326],{"class":217},[211,715,716],{"class":329},"POST",[211,718,333],{"class":217},[211,720,336],{"class":217},[211,722,723],{"class":339},"\u002Flogin",[211,725,336],{"class":217},[211,727,345],{"class":217},[211,729,387],{"class":316},[211,731,326],{"class":217},[211,733,734],{"class":329},"H",[211,736,737],{"class":217},"(func(",[211,739,741],{"class":740},"sHdIc","ctx",[211,743,744],{"class":217}," *",[211,746,747],{"class":221},"ezz",[211,749,326],{"class":217},[211,751,53],{"class":221},[211,753,345],{"class":217},[211,755,756],{"class":740}," req",[211,758,490],{"class":221},[211,760,761],{"class":217},")",[211,763,764],{"class":217}," (*",[211,766,767],{"class":221},"LoginResponse",[211,769,345],{"class":217},[211,771,772],{"class":503}," error",[211,774,761],{"class":217},[211,776,375],{"class":217},[211,778,779,782,784,787,789,792,794,797,799,802,804,806,808,811],{"class":213,"line":225},[211,780,781],{"class":316},"    user",[211,783,345],{"class":217},[211,785,786],{"class":316}," ok ",[211,788,384],{"class":217},[211,790,791],{"class":329}," authenticate",[211,793,333],{"class":217},[211,795,796],{"class":316},"req",[211,798,326],{"class":217},[211,800,801],{"class":316},"Email",[211,803,345],{"class":217},[211,805,756],{"class":316},[211,807,326],{"class":217},[211,809,810],{"class":316},"Password",[211,812,302],{"class":217},[211,814,815,818,821,824],{"class":213,"line":232},[211,816,817],{"class":235},"    if",[211,819,820],{"class":217}," !",[211,822,823],{"class":316},"ok ",[211,825,826],{"class":217},"{\n",[211,828,829,832,835,837,839,842,844,846,849,851],{"class":213,"line":242},[211,830,831],{"class":235},"        return",[211,833,834],{"class":217}," nil,",[211,836,387],{"class":316},[211,838,326],{"class":217},[211,840,841],{"class":329},"Unauthorized",[211,843,333],{"class":217},[211,845,336],{"class":217},[211,847,848],{"class":339},"invalid email or password",[211,850,336],{"class":217},[211,852,302],{"class":217},[211,854,855],{"class":213,"line":254},[211,856,857],{"class":217},"    }\n",[211,859,860],{"class":213,"line":264},[211,861,229],{"emptyLinePlaceholder":228},[211,863,864,867,869,872,874,877,879,882,884,888,890,892,894,897],{"class":213,"line":269},[211,865,866],{"class":316},"    expires ",[211,868,384],{"class":217},[211,870,871],{"class":316}," time",[211,873,326],{"class":217},[211,875,876],{"class":329},"Now",[211,878,395],{"class":217},[211,880,881],{"class":329},"Add",[211,883,333],{"class":217},[211,885,887],{"class":886},"sbssI","24",[211,889,744],{"class":217},[211,891,871],{"class":316},[211,893,326],{"class":217},[211,895,896],{"class":316},"Hour",[211,898,302],{"class":217},[211,900,901,904,906,909,911,914,916,919,922,924,926,929],{"class":213,"line":279},[211,902,903],{"class":316},"    token",[211,905,345],{"class":217},[211,907,908],{"class":316}," err ",[211,910,384],{"class":217},[211,912,913],{"class":316}," jwt",[211,915,326],{"class":217},[211,917,918],{"class":329},"GenerateToken",[211,920,921],{"class":217},"(&",[211,923,402],{"class":221},[211,925,326],{"class":217},[211,927,928],{"class":221},"Claims",[211,930,826],{"class":217},[211,932,933,936,939,942,944,947],{"class":213,"line":289},[211,934,935],{"class":316},"        Subject",[211,937,938],{"class":217},":",[211,940,941],{"class":316},"   user",[211,943,326],{"class":217},[211,945,946],{"class":316},"ID",[211,948,949],{"class":217},",\n",[211,951,952,955,957,960,962,965],{"class":213,"line":299},[211,953,954],{"class":316},"        ExpiresAt",[211,956,938],{"class":217},[211,958,959],{"class":316}," expires",[211,961,326],{"class":217},[211,963,964],{"class":329},"Unix",[211,966,967],{"class":217},"(),\n",[211,969,970,973,975,978,980,983,986,989,991,994,996,998,1001,1003,1006],{"class":213,"line":305},[211,971,972],{"class":316},"        Custom",[211,974,938],{"class":217},[211,976,977],{"class":217},"    map[",[211,979,504],{"class":503},[211,981,982],{"class":217},"]",[211,984,985],{"class":221},"any",[211,987,988],{"class":217},"{",[211,990,336],{"class":217},[211,992,993],{"class":339},"role",[211,995,336],{"class":217},[211,997,938],{"class":217},[211,999,1000],{"class":316}," user",[211,1002,326],{"class":217},[211,1004,1005],{"class":316},"Role",[211,1007,1008],{"class":217},"},\n",[211,1010,1011],{"class":213,"line":310},[211,1012,1013],{"class":217},"    })\n",[211,1015,1016,1018,1020,1023,1026],{"class":213,"line":358},[211,1017,817],{"class":235},[211,1019,908],{"class":316},[211,1021,1022],{"class":217},"!=",[211,1024,1025],{"class":217}," nil",[211,1027,375],{"class":217},[211,1029,1030,1032,1034,1036,1038,1041,1043,1045,1048,1050],{"class":213,"line":363},[211,1031,831],{"class":235},[211,1033,834],{"class":217},[211,1035,387],{"class":316},[211,1037,326],{"class":217},[211,1039,1040],{"class":329},"InternalServerError",[211,1042,333],{"class":217},[211,1044,336],{"class":217},[211,1046,1047],{"class":339},"could not issue token",[211,1049,336],{"class":217},[211,1051,302],{"class":217},[211,1053,1054],{"class":213,"line":378},[211,1055,857],{"class":217},[211,1057,1058],{"class":213,"line":418},[211,1059,229],{"emptyLinePlaceholder":228},[211,1061,1062,1065,1068,1070,1072,1075,1077,1080,1082,1085,1087,1089,1092],{"class":213,"line":423},[211,1063,1064],{"class":235},"    return",[211,1066,1067],{"class":217}," &",[211,1069,767],{"class":221},[211,1071,988],{"class":217},[211,1073,1074],{"class":316},"Token",[211,1076,938],{"class":217},[211,1078,1079],{"class":316}," token",[211,1081,345],{"class":217},[211,1083,1084],{"class":316}," ExpiresAt",[211,1086,938],{"class":217},[211,1088,959],{"class":316},[211,1090,1091],{"class":217},"},",[211,1093,1094],{"class":217}," nil\n",[211,1096,1097,1100,1103,1105,1108,1110,1112,1114,1116],{"class":213,"line":430},[211,1098,1099],{"class":217},"})).",[211,1101,1102],{"class":329},"Public",[211,1104,395],{"class":217},[211,1106,1107],{"class":329},"Tags",[211,1109,333],{"class":217},[211,1111,336],{"class":217},[211,1113,68],{"class":339},[211,1115,336],{"class":217},[211,1117,302],{"class":217},[186,1119,1121],{"id":1120},"group-the-protected-routes","Group the protected routes",[178,1123,1124],{},"A group shares a path prefix, and optionally middleware and an auth rule. Routes inside it inherit the app default, which is \"any valid token\".",[201,1126,1128],{"className":203,"code":1127,"filename":205,"language":206,"meta":207,"style":207},"api := app.Group(\"\u002Fapi\u002Fv1\")\n\napi.GET(\"\u002Fme\", ezz.HFunc(func(ctx *ezz.Context) (*User, error) {\n    user := ctx.User().(auth.User)\n    return lookup(user.ID())\n})).Tags(\"Users\")\n\napi.GET(\"\u002Fusers\u002F{id}\", ezz.H(func(ctx *ezz.Context, req GetUserRequest) (*User, error) {\n    user, ok := store[req.ID]\n    if !ok {\n        return nil, ezz.NotFound(\"user not found\")\n    }\n    return user, nil\n})).Tags(\"Users\")\n",[193,1129,1130,1156,1160,1215,1240,1259,1276,1280,1337,1362,1372,1396,1400,1410],{"__ignoreMap":207},[211,1131,1132,1135,1137,1140,1142,1145,1147,1149,1152,1154],{"class":213,"line":214},[211,1133,1134],{"class":316},"api ",[211,1136,384],{"class":217},[211,1138,1139],{"class":316}," app",[211,1141,326],{"class":217},[211,1143,1144],{"class":329},"Group",[211,1146,333],{"class":217},[211,1148,336],{"class":217},[211,1150,1151],{"class":339},"\u002Fapi\u002Fv1",[211,1153,336],{"class":217},[211,1155,302],{"class":217},[211,1157,1158],{"class":213,"line":225},[211,1159,229],{"emptyLinePlaceholder":228},[211,1161,1162,1165,1167,1170,1172,1174,1177,1179,1181,1183,1185,1188,1190,1192,1194,1196,1198,1200,1202,1204,1207,1209,1211,1213],{"class":213,"line":232},[211,1163,1164],{"class":316},"api",[211,1166,326],{"class":217},[211,1168,1169],{"class":329},"GET",[211,1171,333],{"class":217},[211,1173,336],{"class":217},[211,1175,1176],{"class":339},"\u002Fme",[211,1178,336],{"class":217},[211,1180,345],{"class":217},[211,1182,387],{"class":316},[211,1184,326],{"class":217},[211,1186,1187],{"class":329},"HFunc",[211,1189,737],{"class":217},[211,1191,741],{"class":740},[211,1193,744],{"class":217},[211,1195,747],{"class":221},[211,1197,326],{"class":217},[211,1199,53],{"class":221},[211,1201,761],{"class":217},[211,1203,764],{"class":217},[211,1205,1206],{"class":221},"User",[211,1208,345],{"class":217},[211,1210,772],{"class":503},[211,1212,761],{"class":217},[211,1214,375],{"class":217},[211,1216,1217,1220,1222,1225,1227,1229,1232,1234,1236,1238],{"class":213,"line":242},[211,1218,1219],{"class":316},"    user ",[211,1221,384],{"class":217},[211,1223,1224],{"class":316}," ctx",[211,1226,326],{"class":217},[211,1228,1206],{"class":329},[211,1230,1231],{"class":217},"().(",[211,1233,402],{"class":221},[211,1235,326],{"class":217},[211,1237,1206],{"class":221},[211,1239,302],{"class":217},[211,1241,1242,1244,1247,1249,1252,1254,1256],{"class":213,"line":254},[211,1243,1064],{"class":235},[211,1245,1246],{"class":329}," lookup",[211,1248,333],{"class":217},[211,1250,1251],{"class":316},"user",[211,1253,326],{"class":217},[211,1255,946],{"class":329},[211,1257,1258],{"class":217},"())\n",[211,1260,1261,1263,1265,1267,1269,1272,1274],{"class":213,"line":264},[211,1262,1099],{"class":217},[211,1264,1107],{"class":329},[211,1266,333],{"class":217},[211,1268,336],{"class":217},[211,1270,1271],{"class":339},"Users",[211,1273,336],{"class":217},[211,1275,302],{"class":217},[211,1277,1278],{"class":213,"line":269},[211,1279,229],{"emptyLinePlaceholder":228},[211,1281,1282,1284,1286,1288,1290,1292,1295,1297,1299,1301,1303,1305,1307,1309,1311,1313,1315,1317,1319,1321,1323,1325,1327,1329,1331,1333,1335],{"class":213,"line":279},[211,1283,1164],{"class":316},[211,1285,326],{"class":217},[211,1287,1169],{"class":329},[211,1289,333],{"class":217},[211,1291,336],{"class":217},[211,1293,1294],{"class":339},"\u002Fusers\u002F{id}",[211,1296,336],{"class":217},[211,1298,345],{"class":217},[211,1300,387],{"class":316},[211,1302,326],{"class":217},[211,1304,734],{"class":329},[211,1306,737],{"class":217},[211,1308,741],{"class":740},[211,1310,744],{"class":217},[211,1312,747],{"class":221},[211,1314,326],{"class":217},[211,1316,53],{"class":221},[211,1318,345],{"class":217},[211,1320,756],{"class":740},[211,1322,595],{"class":221},[211,1324,761],{"class":217},[211,1326,764],{"class":217},[211,1328,1206],{"class":221},[211,1330,345],{"class":217},[211,1332,772],{"class":503},[211,1334,761],{"class":217},[211,1336,375],{"class":217},[211,1338,1339,1341,1343,1345,1347,1350,1353,1355,1357,1359],{"class":213,"line":289},[211,1340,781],{"class":316},[211,1342,345],{"class":217},[211,1344,786],{"class":316},[211,1346,384],{"class":217},[211,1348,1349],{"class":316}," store",[211,1351,1352],{"class":217},"[",[211,1354,796],{"class":316},[211,1356,326],{"class":217},[211,1358,946],{"class":316},[211,1360,1361],{"class":217},"]\n",[211,1363,1364,1366,1368,1370],{"class":213,"line":299},[211,1365,817],{"class":235},[211,1367,820],{"class":217},[211,1369,823],{"class":316},[211,1371,826],{"class":217},[211,1373,1374,1376,1378,1380,1382,1385,1387,1389,1392,1394],{"class":213,"line":305},[211,1375,831],{"class":235},[211,1377,834],{"class":217},[211,1379,387],{"class":316},[211,1381,326],{"class":217},[211,1383,1384],{"class":329},"NotFound",[211,1386,333],{"class":217},[211,1388,336],{"class":217},[211,1390,1391],{"class":339},"user not found",[211,1393,336],{"class":217},[211,1395,302],{"class":217},[211,1397,1398],{"class":213,"line":310},[211,1399,857],{"class":217},[211,1401,1402,1404,1406,1408],{"class":213,"line":358},[211,1403,1064],{"class":235},[211,1405,1000],{"class":316},[211,1407,345],{"class":217},[211,1409,1094],{"class":217},[211,1411,1412,1414,1416,1418,1420,1422,1424],{"class":213,"line":363},[211,1413,1099],{"class":217},[211,1415,1107],{"class":329},[211,1417,333],{"class":217},[211,1419,336],{"class":217},[211,1421,1271],{"class":339},[211,1423,336],{"class":217},[211,1425,302],{"class":217},[186,1427,1429],{"id":1428},"restrict-a-route-to-admins","Restrict a route to admins",[178,1431,1432,1433,1436,1437,1440,1441,1443,1444,1447],{},"Auth rules can be set per route with ",[193,1434,1435],{},".Auth(...)"," or on a whole group. ",[193,1438,1439],{},"ezz.Role"," checks the user value returned by your provider, which for JWT tokens reads the ",[193,1442,993],{}," and ",[193,1445,1446],{},"roles"," claims unless you configure a resolver.",[201,1449,1451],{"className":203,"code":1450,"filename":205,"language":206,"meta":207,"style":207},"admin := api.Group(\"\u002Fadmin\").Auth(ezz.Role(\"admin\"))\n\nadmin.DELETE(\"\u002Fusers\u002F{id}\", ezz.H(func(ctx *ezz.Context, req GetUserRequest) (*User, error) {\n    user, ok := store[req.ID]\n    if !ok {\n        return nil, ezz.NotFound(\"user not found\")\n    }\n    delete(store, req.ID)\n    return user, nil\n})).Tags(\"Users\", \"Admin\")\n",[193,1452,1453,1500,1504,1561,1583,1593,1615,1619,1639,1649],{"__ignoreMap":207},[211,1454,1455,1458,1460,1463,1465,1467,1469,1471,1474,1476,1479,1481,1483,1485,1487,1489,1491,1493,1496,1498],{"class":213,"line":214},[211,1456,1457],{"class":316},"admin ",[211,1459,384],{"class":217},[211,1461,1462],{"class":316}," api",[211,1464,326],{"class":217},[211,1466,1144],{"class":329},[211,1468,333],{"class":217},[211,1470,336],{"class":217},[211,1472,1473],{"class":339},"\u002Fadmin",[211,1475,336],{"class":217},[211,1477,1478],{"class":217},").",[211,1480,68],{"class":329},[211,1482,333],{"class":217},[211,1484,747],{"class":316},[211,1486,326],{"class":217},[211,1488,1005],{"class":329},[211,1490,333],{"class":217},[211,1492,336],{"class":217},[211,1494,1495],{"class":339},"admin",[211,1497,336],{"class":217},[211,1499,415],{"class":217},[211,1501,1502],{"class":213,"line":225},[211,1503,229],{"emptyLinePlaceholder":228},[211,1505,1506,1508,1510,1513,1515,1517,1519,1521,1523,1525,1527,1529,1531,1533,1535,1537,1539,1541,1543,1545,1547,1549,1551,1553,1555,1557,1559],{"class":213,"line":232},[211,1507,1495],{"class":316},[211,1509,326],{"class":217},[211,1511,1512],{"class":329},"DELETE",[211,1514,333],{"class":217},[211,1516,336],{"class":217},[211,1518,1294],{"class":339},[211,1520,336],{"class":217},[211,1522,345],{"class":217},[211,1524,387],{"class":316},[211,1526,326],{"class":217},[211,1528,734],{"class":329},[211,1530,737],{"class":217},[211,1532,741],{"class":740},[211,1534,744],{"class":217},[211,1536,747],{"class":221},[211,1538,326],{"class":217},[211,1540,53],{"class":221},[211,1542,345],{"class":217},[211,1544,756],{"class":740},[211,1546,595],{"class":221},[211,1548,761],{"class":217},[211,1550,764],{"class":217},[211,1552,1206],{"class":221},[211,1554,345],{"class":217},[211,1556,772],{"class":503},[211,1558,761],{"class":217},[211,1560,375],{"class":217},[211,1562,1563,1565,1567,1569,1571,1573,1575,1577,1579,1581],{"class":213,"line":242},[211,1564,781],{"class":316},[211,1566,345],{"class":217},[211,1568,786],{"class":316},[211,1570,384],{"class":217},[211,1572,1349],{"class":316},[211,1574,1352],{"class":217},[211,1576,796],{"class":316},[211,1578,326],{"class":217},[211,1580,946],{"class":316},[211,1582,1361],{"class":217},[211,1584,1585,1587,1589,1591],{"class":213,"line":254},[211,1586,817],{"class":235},[211,1588,820],{"class":217},[211,1590,823],{"class":316},[211,1592,826],{"class":217},[211,1594,1595,1597,1599,1601,1603,1605,1607,1609,1611,1613],{"class":213,"line":264},[211,1596,831],{"class":235},[211,1598,834],{"class":217},[211,1600,387],{"class":316},[211,1602,326],{"class":217},[211,1604,1384],{"class":329},[211,1606,333],{"class":217},[211,1608,336],{"class":217},[211,1610,1391],{"class":339},[211,1612,336],{"class":217},[211,1614,302],{"class":217},[211,1616,1617],{"class":213,"line":269},[211,1618,857],{"class":217},[211,1620,1621,1624,1626,1629,1631,1633,1635,1637],{"class":213,"line":279},[211,1622,1623],{"class":329},"    delete",[211,1625,333],{"class":217},[211,1627,1628],{"class":316},"store",[211,1630,345],{"class":217},[211,1632,756],{"class":316},[211,1634,326],{"class":217},[211,1636,946],{"class":316},[211,1638,302],{"class":217},[211,1640,1641,1643,1645,1647],{"class":213,"line":289},[211,1642,1064],{"class":235},[211,1644,1000],{"class":316},[211,1646,345],{"class":217},[211,1648,1094],{"class":217},[211,1650,1651,1653,1655,1657,1659,1661,1663,1665,1667,1670,1672],{"class":213,"line":299},[211,1652,1099],{"class":217},[211,1654,1107],{"class":329},[211,1656,333],{"class":217},[211,1658,336],{"class":217},[211,1660,1271],{"class":339},[211,1662,336],{"class":217},[211,1664,345],{"class":217},[211,1666,348],{"class":217},[211,1668,1669],{"class":339},"Admin",[211,1671,336],{"class":217},[211,1673,302],{"class":217},[186,1675,1677],{"id":1676},"serve-the-documentation","Serve the documentation",[178,1679,1680,1681,1684,1685,1688],{},"This registers ",[193,1682,1683],{},"\u002Fopenapi.json"," and a Scalar UI at ",[193,1686,1687],{},"\u002Fdocs",", both public.",[201,1690,1692],{"className":203,"code":1691,"filename":205,"language":206,"meta":207,"style":207},"openapi.SetupDocsEndpoints(app, openapi.ScalarConfig{\n    Title:    \"Quick Start API\",\n    Layout:   \"modern\",\n    DarkMode: true,\n})\n",[193,1693,1694,1720,1736,1753,1766],{"__ignoreMap":207},[211,1695,1696,1699,1701,1704,1706,1708,1710,1713,1715,1718],{"class":213,"line":214},[211,1697,1698],{"class":316},"openapi",[211,1700,326],{"class":217},[211,1702,1703],{"class":329},"SetupDocsEndpoints",[211,1705,333],{"class":217},[211,1707,448],{"class":316},[211,1709,345],{"class":217},[211,1711,1712],{"class":221}," openapi",[211,1714,326],{"class":217},[211,1716,1717],{"class":221},"ScalarConfig",[211,1719,826],{"class":217},[211,1721,1722,1725,1727,1729,1732,1734],{"class":213,"line":225},[211,1723,1724],{"class":316},"    Title",[211,1726,938],{"class":217},[211,1728,245],{"class":217},[211,1730,1731],{"class":339},"Quick Start API",[211,1733,336],{"class":217},[211,1735,949],{"class":217},[211,1737,1738,1741,1743,1746,1749,1751],{"class":213,"line":232},[211,1739,1740],{"class":316},"    Layout",[211,1742,938],{"class":217},[211,1744,1745],{"class":217},"   \"",[211,1747,1748],{"class":339},"modern",[211,1750,336],{"class":217},[211,1752,949],{"class":217},[211,1754,1755,1758,1760,1764],{"class":213,"line":242},[211,1756,1757],{"class":316},"    DarkMode",[211,1759,938],{"class":217},[211,1761,1763],{"class":1762},"sfNiH"," true",[211,1765,949],{"class":217},[211,1767,1768],{"class":213,"line":254},[211,1769,1770],{"class":217},"})\n",[186,1772,1774],{"id":1773},"try-it","Try it",[201,1776,1781],{"className":1777,"code":1778,"filename":1779,"language":1780,"meta":207,"style":207},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# no token, so this is rejected\ncurl -i localhost:8080\u002Fapi\u002Fv1\u002Fme\n\n# log in and keep the token\nTOKEN=$(curl -s localhost:8080\u002Flogin \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"email\":\"ada@example.com\",\"password\":\"password123\"}' | jq -r .token)\n\n# now the protected route answers\ncurl -s localhost:8080\u002Fapi\u002Fv1\u002Fme -H \"Authorization: Bearer $TOKEN\"\n\n# validation runs before your handler\ncurl -s localhost:8080\u002Flogin \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"email\":\"nope\",\"password\":\"short\"}'\n","Terminal","bash",[193,1782,1783,1788,1799,1803,1808,1827,1843,1869,1873,1878,1900,1904,1909,1919,1931],{"__ignoreMap":207},[211,1784,1785],{"class":213,"line":214},[211,1786,1787],{"class":426},"# no token, so this is rejected\n",[211,1789,1790,1793,1796],{"class":213,"line":225},[211,1791,1792],{"class":221},"curl",[211,1794,1795],{"class":339}," -i",[211,1797,1798],{"class":339}," localhost:8080\u002Fapi\u002Fv1\u002Fme\n",[211,1800,1801],{"class":213,"line":232},[211,1802,229],{"emptyLinePlaceholder":228},[211,1804,1805],{"class":213,"line":242},[211,1806,1807],{"class":426},"# log in and keep the token\n",[211,1809,1810,1813,1816,1818,1821,1824],{"class":213,"line":254},[211,1811,1812],{"class":316},"TOKEN",[211,1814,1815],{"class":217},"=$(",[211,1817,1792],{"class":221},[211,1819,1820],{"class":339}," -s",[211,1822,1823],{"class":339}," localhost:8080\u002Flogin",[211,1825,1826],{"class":316}," \\\n",[211,1828,1829,1832,1835,1838,1841],{"class":213,"line":264},[211,1830,1831],{"class":339},"  -H",[211,1833,1834],{"class":217}," '",[211,1836,1837],{"class":339},"Content-Type: application\u002Fjson",[211,1839,1840],{"class":217},"'",[211,1842,1826],{"class":316},[211,1844,1845,1848,1850,1853,1855,1858,1861,1864,1867],{"class":213,"line":269},[211,1846,1847],{"class":339},"  -d",[211,1849,1834],{"class":217},[211,1851,1852],{"class":339},"{\"email\":\"ada@example.com\",\"password\":\"password123\"}",[211,1854,1840],{"class":217},[211,1856,1857],{"class":217}," |",[211,1859,1860],{"class":221}," jq",[211,1862,1863],{"class":339}," -r",[211,1865,1866],{"class":339}," .token",[211,1868,302],{"class":217},[211,1870,1871],{"class":213,"line":279},[211,1872,229],{"emptyLinePlaceholder":228},[211,1874,1875],{"class":213,"line":289},[211,1876,1877],{"class":426},"# now the protected route answers\n",[211,1879,1880,1882,1884,1887,1890,1892,1895,1898],{"class":213,"line":299},[211,1881,1792],{"class":221},[211,1883,1820],{"class":339},[211,1885,1886],{"class":339}," localhost:8080\u002Fapi\u002Fv1\u002Fme",[211,1888,1889],{"class":339}," -H",[211,1891,348],{"class":217},[211,1893,1894],{"class":339},"Authorization: Bearer ",[211,1896,1897],{"class":316},"$TOKEN",[211,1899,251],{"class":217},[211,1901,1902],{"class":213,"line":305},[211,1903,229],{"emptyLinePlaceholder":228},[211,1905,1906],{"class":213,"line":310},[211,1907,1908],{"class":426},"# validation runs before your handler\n",[211,1910,1911,1913,1915,1917],{"class":213,"line":358},[211,1912,1792],{"class":221},[211,1914,1820],{"class":339},[211,1916,1823],{"class":339},[211,1918,1826],{"class":316},[211,1920,1921,1923,1925,1927,1929],{"class":213,"line":363},[211,1922,1831],{"class":339},[211,1924,1834],{"class":217},[211,1926,1837],{"class":339},[211,1928,1840],{"class":217},[211,1930,1826],{"class":316},[211,1932,1933,1935,1937,1940],{"class":213,"line":378},[211,1934,1847],{"class":339},[211,1936,1834],{"class":217},[211,1938,1939],{"class":339},"{\"email\":\"nope\",\"password\":\"short\"}",[211,1941,1942],{"class":217},"'\n",[178,1944,1945,1946,1949],{},"The last call returns a ",[193,1947,1948],{},"400"," and a body like:",[201,1951,1955],{"className":1952,"code":1953,"language":1954,"meta":207,"style":207},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"error\": true,\n  \"message\": \"field 'Email' must be a valid email; field 'Password' must be at least 8\",\n  \"status\": 400\n}\n","json",[193,1956,1957,1961,1976,1996,2010],{"__ignoreMap":207},[211,1958,1959],{"class":213,"line":214},[211,1960,826],{"class":217},[211,1962,1963,1966,1969,1971,1973],{"class":213,"line":225},[211,1964,1965],{"class":217},"  \"",[211,1967,1968],{"class":503},"error",[211,1970,336],{"class":217},[211,1972,938],{"class":217},[211,1974,1975],{"class":217}," true,\n",[211,1977,1978,1980,1983,1985,1987,1989,1992,1994],{"class":213,"line":232},[211,1979,1965],{"class":217},[211,1981,1982],{"class":503},"message",[211,1984,336],{"class":217},[211,1986,938],{"class":217},[211,1988,348],{"class":217},[211,1990,1991],{"class":339},"field 'Email' must be a valid email; field 'Password' must be at least 8",[211,1993,336],{"class":217},[211,1995,949],{"class":217},[211,1997,1998,2000,2003,2005,2007],{"class":213,"line":242},[211,1999,1965],{"class":217},[211,2001,2002],{"class":503},"status",[211,2004,336],{"class":217},[211,2006,938],{"class":217},[211,2008,2009],{"class":886}," 400\n",[211,2011,2012],{"class":213,"line":254},[211,2013,470],{"class":217},[178,2015,2016,2017,2020,2021,2024,2025,2024,2028,2031,2032,2035],{},"Open ",[193,2018,2019],{},"http:\u002F\u002Flocalhost:8080\u002Fdocs"," and you will find every route, with path parameters, request bodies, response schemas, and the ",[193,2022,2023],{},"min","\u002F",[193,2026,2027],{},"max",[193,2029,2030],{},"email"," constraints carried over from the ",[193,2033,2034],{},"validate"," tags.",[186,2037,2039],{"id":2038},"what-to-read-next","What to read next",[2041,2042,2043,2056],"table",{},[2044,2045,2046],"thead",{},[2047,2048,2049,2053],"tr",{},[2050,2051,2052],"th",{},"If you want to",[2050,2054,2055],{},"Read",[2057,2058,2059,2070,2080,2090,2100],"tbody",{},[2047,2060,2061,2065],{},[2062,2063,2064],"td",{},"Understand patterns, groups, and route metadata",[2062,2066,2067],{},[2068,2069,33],"a",{"href":34},[2047,2071,2072,2075],{},[2062,2073,2074],{},"Bind headers, forms, or repeated query parameters",[2062,2076,2077],{},[2068,2078,2079],{"href":44},"Request binding",[2047,2081,2082,2085],{},[2062,2083,2084],{},"Load roles and permissions from your database",[2062,2086,2087],{},[2068,2088,2089],{"href":90},"Roles and permissions",[2047,2091,2092,2095],{},[2062,2093,2094],{},"Put GoTrue behind your API",[2062,2096,2097],{},[2068,2098,2099],{"href":106},"GoTrue proxy",[2047,2101,2102,2105],{},[2062,2103,2104],{},"Write tests against the app",[2062,2106,2107],{},[2068,2108,147],{"href":148},[2110,2111,2112],"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 .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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":207,"searchDepth":225,"depth":225,"links":2114},[2115,2116,2117,2118,2119,2120,2121,2122],{"id":188,"depth":225,"text":189},{"id":473,"depth":225,"text":474},{"id":695,"depth":225,"text":696},{"id":1120,"depth":225,"text":1121},{"id":1428,"depth":225,"text":1429},{"id":1676,"depth":225,"text":1677},{"id":1773,"depth":225,"text":1774},{"id":2038,"depth":225,"text":2039},"Build an authenticated JSON API with generated OpenAPI docs in one file.","md",null,{},{"icon":24},{"title":21,"description":2123},"qluRRaiGLri9qO4P_Jm0dCrVczu0MitQZRKGH6DrQ-g",[2131,2133],{"title":16,"path":17,"stem":18,"description":2132,"icon":19,"children":-1},"Add ezz to a Go module and verify it serves a request.",{"title":33,"path":34,"stem":35,"description":2134,"icon":36,"children":-1},"Register routes, use path patterns, group them, and attach metadata.",1784970045270]