[{"data":1,"prerenderedAt":688},["ShallowReactive",2],{"navigation_docs":3,"landing":172},[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":174,"body":175,"description":174,"extension":680,"meta":681,"navigation":298,"path":682,"seo":683,"stem":686,"__hash__":687},"landing\u002Findex.md","",{"type":176,"value":177,"toc":678},"minimark",[178,220,547,660,674],[179,180,181,193,196,204],"u-page-hero",{},[182,183,184],"template",{"v-slot:headline":174},[185,186],"u-color-mode-image",{"alt":187,"className":188,"dark":191,"light":192},"ezz",[189,190],"size-14","mx-auto","\u002Flogo\u002Fezz-mark-dark.svg","\u002Flogo\u002Fezz-mark.svg",[182,194,195],{"v-slot:title":174},"Typed HTTP APIs in Go",[182,197,198,199,203],{"v-slot:description":174},"ezz sits on top of ",[200,201,202],"code",{},"net\u002Fhttp",". Your handler takes a typed request and returns a typed response; the framework binds the request from struct tags, validates it, checks the caller's roles, and generates the OpenAPI spec from the same types.",[182,205,206,213],{"v-slot:links":174},[207,208,212],"u-button",{"color":209,"size":210,"to":12,"trailing-icon":211},"neutral","xl","i-lucide-arrow-right","Get started",[207,214,219],{"color":209,"size":210,"to":215,"icon":216,"target":217,"variant":218},"https:\u002F\u002Fgithub.com\u002Fsulv-io\u002Fezz","i-simple-icons-github","_blank","outline","View on GitHub",[221,222,223,534,537],"u-page-section",{},[224,225,230],"pre",{"className":226,"code":227,"filename":228,"language":229,"meta":174,"style":174},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","type GetUserRequest struct {\n    ID     string `path:\"id\" validate:\"required\" description:\"User ID\"`\n    Fields string `query:\"fields\" default:\"basic\"`\n}\n\napp := ezz.New().Auth(auth.NewJWTAuthProvider(jwt))\n\napp.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","main.go","go",[200,231,232,251,272,287,293,300,343,348,420,450,466,494,500,514],{"__ignoreMap":174},[233,234,237,241,245,248],"span",{"class":235,"line":236},"line",1,[233,238,240],{"class":239},"sMK4o","type",[233,242,244],{"class":243},"sBMFI"," GetUserRequest",[233,246,247],{"class":239}," struct",[233,249,250],{"class":239}," {\n",[233,252,254,258,262,265,269],{"class":235,"line":253},2,[233,255,257],{"class":256},"sTEyZ","    ID     ",[233,259,261],{"class":260},"spNyl","string",[233,263,264],{"class":239}," `",[233,266,268],{"class":267},"sfazB","path:\"id\" validate:\"required\" description:\"User ID\"",[233,270,271],{"class":239},"`\n",[233,273,275,278,280,282,285],{"class":235,"line":274},3,[233,276,277],{"class":256},"    Fields ",[233,279,261],{"class":260},[233,281,264],{"class":239},[233,283,284],{"class":267},"query:\"fields\" default:\"basic\"",[233,286,271],{"class":239},[233,288,290],{"class":235,"line":289},4,[233,291,292],{"class":239},"}\n",[233,294,296],{"class":235,"line":295},5,[233,297,299],{"emptyLinePlaceholder":298},true,"\n",[233,301,303,306,309,312,315,319,322,324,327,330,332,335,337,340],{"class":235,"line":302},6,[233,304,305],{"class":256},"app ",[233,307,308],{"class":239},":=",[233,310,311],{"class":256}," ezz",[233,313,314],{"class":239},".",[233,316,318],{"class":317},"s2Zo4","New",[233,320,321],{"class":239},"().",[233,323,68],{"class":317},[233,325,326],{"class":239},"(",[233,328,329],{"class":256},"auth",[233,331,314],{"class":239},[233,333,334],{"class":317},"NewJWTAuthProvider",[233,336,326],{"class":239},[233,338,339],{"class":256},"jwt",[233,341,342],{"class":239},"))\n",[233,344,346],{"class":235,"line":345},7,[233,347,299],{"emptyLinePlaceholder":298},[233,349,351,354,356,359,361,364,367,369,372,374,376,379,382,386,389,391,393,395,397,400,402,405,408,411,413,416,418],{"class":235,"line":350},8,[233,352,353],{"class":256},"app",[233,355,314],{"class":239},[233,357,358],{"class":317},"GET",[233,360,326],{"class":239},[233,362,363],{"class":239},"\"",[233,365,366],{"class":267},"\u002Fusers\u002F{id}",[233,368,363],{"class":239},[233,370,371],{"class":239},",",[233,373,311],{"class":256},[233,375,314],{"class":239},[233,377,378],{"class":317},"H",[233,380,381],{"class":239},"(func(",[233,383,385],{"class":384},"sHdIc","ctx",[233,387,388],{"class":239}," *",[233,390,187],{"class":243},[233,392,314],{"class":239},[233,394,53],{"class":243},[233,396,371],{"class":239},[233,398,399],{"class":384}," req",[233,401,244],{"class":243},[233,403,404],{"class":239},")",[233,406,407],{"class":239}," (*",[233,409,410],{"class":243},"User",[233,412,371],{"class":239},[233,414,415],{"class":260}," error",[233,417,404],{"class":239},[233,419,250],{"class":239},[233,421,423,426,428,431,433,436,439,442,444,447],{"class":235,"line":422},9,[233,424,425],{"class":256},"    user",[233,427,371],{"class":239},[233,429,430],{"class":256}," ok ",[233,432,308],{"class":239},[233,434,435],{"class":256}," store",[233,437,438],{"class":239},"[",[233,440,441],{"class":256},"req",[233,443,314],{"class":239},[233,445,446],{"class":256},"ID",[233,448,449],{"class":239},"]\n",[233,451,453,457,460,463],{"class":235,"line":452},10,[233,454,456],{"class":455},"s7zQu","    if",[233,458,459],{"class":239}," !",[233,461,462],{"class":256},"ok ",[233,464,465],{"class":239},"{\n",[233,467,469,472,475,477,479,482,484,486,489,491],{"class":235,"line":468},11,[233,470,471],{"class":455},"        return",[233,473,474],{"class":239}," nil,",[233,476,311],{"class":256},[233,478,314],{"class":239},[233,480,481],{"class":317},"NotFound",[233,483,326],{"class":239},[233,485,363],{"class":239},[233,487,488],{"class":267},"user not found",[233,490,363],{"class":239},[233,492,493],{"class":239},")\n",[233,495,497],{"class":235,"line":496},12,[233,498,499],{"class":239},"    }\n",[233,501,503,506,509,511],{"class":235,"line":502},13,[233,504,505],{"class":455},"    return",[233,507,508],{"class":256}," user",[233,510,371],{"class":239},[233,512,513],{"class":239}," nil\n",[233,515,517,520,523,525,527,530,532],{"class":235,"line":516},14,[233,518,519],{"class":239},"})).",[233,521,522],{"class":317},"Tags",[233,524,326],{"class":239},[233,526,363],{"class":239},[233,528,529],{"class":267},"Users",[233,531,363],{"class":239},[233,533,493],{"class":239},[182,535,536],{"v-slot:title":174},"One type, four jobs",[182,538,539,542,543,546],{"v-slot:description":174},[200,540,541],{},"GetUserRequest"," describes the path parameter and the query string, so ezz can bind it, validate it, document it in ",[200,544,545],{},"\u002Fopenapi.json",", and hand your function a filled-in struct. There is no code generation step and no reflection on the request path.",[221,548,551,567,593,605,614,625,637,648],{"description":549,"title":550},"Every part of the framework works with plain net\u002Fhttp types, so you can drop down a level whenever you need to.","What you get",[552,553,554,557],"u-page-feature",{"icon":41,"to":39},[182,555,556],{"v-slot:title":174},"Typed handlers",[182,558,559,562,563,566],{"v-slot:description":174},[200,560,561],{},"ezz.H"," and ",[200,564,565],{},"ezz.HFunc"," give you generic handlers with compile-time request and response types. Binders and validators are built once at registration.",[552,568,569,572],{"icon":46,"to":44},[182,570,571],{"v-slot:title":174},"Tag-driven binding",[182,573,574,575,578,579,578,582,578,585,588,589,592],{"v-slot:description":174},"Read values from the path, query string, headers, form fields, and JSON body with ",[200,576,577],{},"path",", ",[200,580,581],{},"query",[200,583,584],{},"header",[200,586,587],{},"form",", and ",[200,590,591],{},"default"," tags.",[552,594,595,598],{"icon":69,"to":75},[182,596,597],{"v-slot:title":174},"Auth on by default",[182,599,600,601,604],{"v-slot:description":174},"Set an auth provider and every route requires a valid token until you mark it ",[200,602,603],{},".Public()",". Roles and permissions are route-level rules.",[552,606,608,611],{"icon":607,"to":90},"i-lucide-database",[182,609,610],{"v-slot:title":174},"Authorization from your own tables",[182,612,613],{"v-slot:description":174},"An authorization resolver loads roles and permissions from your store, lazily and once per request, with an optional TTL cache.",[552,615,616,619],{"icon":134,"to":132},[182,617,618],{"v-slot:title":174},"OpenAPI from your types",[182,620,621,622,314],{"v-slot:description":174},"The spec is generated from handler signatures, struct tags, and validation rules, and served next to a Scalar UI at ",[200,623,624],{},"\u002Fdocs",[552,626,627,630],{"icon":100,"to":106},[182,628,629],{"v-slot:title":174},"GoTrue proxy",[182,631,632,633,636],{"v-slot:description":174},"Keep GoTrue on a private network and expose typed, documented, rate-limited ",[200,634,635],{},"\u002Fauth\u002F*"," routes through your own service.",[552,638,639,642],{"icon":66,"to":64},[182,640,641],{"v-slot:title":174},"Middleware you already know",[182,643,644,647],{"v-slot:description":174},[200,645,646],{},"func(http.Handler) http.Handler",". Recovery, request IDs, and logging are installed by default; CORS, gzip, and rate limiting ship alongside.",[552,649,650,653],{"icon":155,"to":153},[182,651,652],{"v-slot:title":174},"Cheap request path",[182,654,655,656,659],{"v-slot:description":174},"Pooled contexts and response writers, middleware chains compiled at registration, and Go's own ",[200,657,658],{},"ServeMux"," for routing.",[221,661,662,665,668],{},[182,663,664],{"v-slot:title":174},"Ready to build something?",[182,666,667],{"v-slot:description":174},"Install the module, copy the quick start, and you have a documented, authenticated JSON API in about thirty lines.",[182,669,670],{"v-slot:links":174},[207,671,673],{"color":209,"size":672,"to":22,"trailing-icon":211},"lg","Read the quick start",[675,676,677],"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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .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 .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);}",{"title":174,"searchDepth":253,"depth":253,"links":679},[],"md",{},"\u002F",{"title":684,"description":685},"ezz, a typed HTTP framework for Go","Write Go handlers that take a typed request and return a typed response. ezz binds and validates the request, enforces auth, and generates the OpenAPI spec from your types.","index","mgQOu7hm65jOqQkZUj_0E-wisSOOMMUCV2kQmc6NEyA",1784970044726]