[{"data":1,"prerenderedAt":630},["ShallowReactive",2],{"navigation_docs":3,"-getting-started-introduction":172,"-getting-started-introduction-surround":627},[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":11,"body":174,"description":620,"extension":621,"links":622,"meta":623,"navigation":624,"path":12,"seo":625,"stem":13,"__hash__":626},"docs\u002F1.getting-started\u002F1.introduction.md",{"type":175,"value":176,"toc":613},"minimark",[177,181,205,210,259,263,523,535,539,542,548,552,588,592,609],[178,179,180],"p",{},"ezz is a Go framework for JSON APIs. You write a function that takes a typed request struct and returns a typed response, register it on a route, and ezz takes care of the parts that are the same in every service: reading values out of the request, validating them, rejecting unauthenticated callers, shaping errors, and describing the endpoint in an OpenAPI document.",[178,182,183,184,188,189,192,193,196,197,200,201,204],{},"It is a thin layer, not a platform. Routing is Go's own ",[185,186,187],"code",{},"net\u002Fhttp.ServeMux",". Middleware is ",[185,190,191],{},"func(http.Handler) http.Handler",". An ",[185,194,195],{},"*ezz.App"," is an ",[185,198,199],{},"http.Handler",", and every handler you write is one too, so you can mix ezz code with plain ",[185,202,203],{},"net\u002Fhttp"," code in the same binary.",[206,207,209],"h2",{"id":208},"what-ezz-does-for-you","What ezz does for you",[211,212,213,221,235,241,247,253],"ul",{},[214,215,216,220],"li",{},[217,218,219],"strong",{},"Binds requests."," Struct tags map path segments, query parameters, headers, form fields, and the JSON body onto your request type.",[214,222,223,226,227,230,231,234],{},[217,224,225],{},"Validates input."," A ",[185,228,229],{},"validate"," tag rejects bad input with a ",[185,232,233],{},"400"," before your function runs.",[214,236,237,240],{},[217,238,239],{},"Authenticates and authorizes."," Register an auth provider and routes require a valid token unless you mark them public. Role and permission rules live on the route.",[214,242,243,246],{},[217,244,245],{},"Resolves authorization from your data."," Roles and permissions come from a resolver you implement against your own tables, not from a token claim.",[214,248,249,252],{},[217,250,251],{},"Documents itself."," The OpenAPI 3 spec is generated from your handler types and served next to a Scalar UI.",[214,254,255,258],{},[217,256,257],{},"Fronts GoTrue."," If you use GoTrue or Supabase Auth, ezz can proxy it so the auth server never faces the internet.",[206,260,262],{"id":261},"what-a-handler-looks-like","What a handler looks like",[264,265,271],"pre",{"className":266,"code":267,"filename":268,"language":269,"meta":270,"style":270},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","type CreateUserRequest struct {\n    Name  string `json:\"name\" validate:\"required,min=2,max=100\"`\n    Email string `json:\"email\" validate:\"required,email\"`\n}\n\napp.POST(\"\u002Fusers\", ezz.H(func(ctx *ezz.Context, req CreateUserRequest) (*User, error) {\n    if store.EmailTaken(req.Email) {\n        return nil, ezz.Conflict(\"email already registered\")\n    }\n    return store.Create(req.Name, req.Email), nil\n}))\n","main.go","go","",[185,272,273,292,313,328,334,341,418,447,475,481,517],{"__ignoreMap":270},[274,275,278,282,286,289],"span",{"class":276,"line":277},"line",1,[274,279,281],{"class":280},"sMK4o","type",[274,283,285],{"class":284},"sBMFI"," CreateUserRequest",[274,287,288],{"class":280}," struct",[274,290,291],{"class":280}," {\n",[274,293,295,299,303,306,310],{"class":276,"line":294},2,[274,296,298],{"class":297},"sTEyZ","    Name  ",[274,300,302],{"class":301},"spNyl","string",[274,304,305],{"class":280}," `",[274,307,309],{"class":308},"sfazB","json:\"name\" validate:\"required,min=2,max=100\"",[274,311,312],{"class":280},"`\n",[274,314,316,319,321,323,326],{"class":276,"line":315},3,[274,317,318],{"class":297},"    Email ",[274,320,302],{"class":301},[274,322,305],{"class":280},[274,324,325],{"class":308},"json:\"email\" validate:\"required,email\"",[274,327,312],{"class":280},[274,329,331],{"class":276,"line":330},4,[274,332,333],{"class":280},"}\n",[274,335,337],{"class":276,"line":336},5,[274,338,340],{"emptyLinePlaceholder":339},true,"\n",[274,342,344,347,350,354,357,360,363,365,368,371,373,376,379,383,386,389,391,393,395,398,400,403,406,409,411,414,416],{"class":276,"line":343},6,[274,345,346],{"class":297},"app",[274,348,349],{"class":280},".",[274,351,353],{"class":352},"s2Zo4","POST",[274,355,356],{"class":280},"(",[274,358,359],{"class":280},"\"",[274,361,362],{"class":308},"\u002Fusers",[274,364,359],{"class":280},[274,366,367],{"class":280},",",[274,369,370],{"class":297}," ezz",[274,372,349],{"class":280},[274,374,375],{"class":352},"H",[274,377,378],{"class":280},"(func(",[274,380,382],{"class":381},"sHdIc","ctx",[274,384,385],{"class":280}," *",[274,387,388],{"class":284},"ezz",[274,390,349],{"class":280},[274,392,53],{"class":284},[274,394,367],{"class":280},[274,396,397],{"class":381}," req",[274,399,285],{"class":284},[274,401,402],{"class":280},")",[274,404,405],{"class":280}," (*",[274,407,408],{"class":284},"User",[274,410,367],{"class":280},[274,412,413],{"class":301}," error",[274,415,402],{"class":280},[274,417,291],{"class":280},[274,419,421,425,428,430,433,435,438,440,443,445],{"class":276,"line":420},7,[274,422,424],{"class":423},"s7zQu","    if",[274,426,427],{"class":297}," store",[274,429,349],{"class":280},[274,431,432],{"class":352},"EmailTaken",[274,434,356],{"class":280},[274,436,437],{"class":297},"req",[274,439,349],{"class":280},[274,441,442],{"class":297},"Email",[274,444,402],{"class":280},[274,446,291],{"class":280},[274,448,450,453,456,458,460,463,465,467,470,472],{"class":276,"line":449},8,[274,451,452],{"class":423},"        return",[274,454,455],{"class":280}," nil,",[274,457,370],{"class":297},[274,459,349],{"class":280},[274,461,462],{"class":352},"Conflict",[274,464,356],{"class":280},[274,466,359],{"class":280},[274,468,469],{"class":308},"email already registered",[274,471,359],{"class":280},[274,473,474],{"class":280},")\n",[274,476,478],{"class":276,"line":477},9,[274,479,480],{"class":280},"    }\n",[274,482,484,487,489,491,494,496,498,500,503,505,507,509,511,514],{"class":276,"line":483},10,[274,485,486],{"class":423},"    return",[274,488,427],{"class":297},[274,490,349],{"class":280},[274,492,493],{"class":352},"Create",[274,495,356],{"class":280},[274,497,437],{"class":297},[274,499,349],{"class":280},[274,501,502],{"class":297},"Name",[274,504,367],{"class":280},[274,506,397],{"class":297},[274,508,349],{"class":280},[274,510,442],{"class":297},[274,512,513],{"class":280},"),",[274,515,516],{"class":280}," nil\n",[274,518,520],{"class":276,"line":519},11,[274,521,522],{"class":280},"}))\n",[178,524,525,526,528,529,531,532,349],{},"By the time your function runs, the body has been decoded, ",[185,527,502],{}," and ",[185,530,442],{}," have been checked, and the caller has been authenticated. Returning an error writes a JSON error body with a matching status code. Returning a value writes it as JSON with ",[185,533,534],{},"200",[206,536,538],{"id":537},"when-to-reach-for-it","When to reach for it",[178,540,541],{},"ezz fits services that speak JSON over HTTP and want types and documentation to stay in sync: internal APIs, mobile and SPA backends, and anything sitting in front of GoTrue. It is a good fit when you like the standard library and want a little structure on top of it.",[178,543,544,545,547],{},"It is not a batteries-included web framework. There is no ORM, no template engine, no asset pipeline, and no background job runner. If you need server-rendered HTML or websockets as a first-class concern, use ezz for the JSON parts and plain ",[185,546,203],{}," for the rest.",[206,549,551],{"id":550},"requirements","Requirements",[211,553,554,565],{},[214,555,556,557,560,561,564],{},"Go 1.22 or newer, for method-aware ",[185,558,559],{},"ServeMux"," patterns and ",[185,562,563],{},"Request.PathValue",". The module itself is built with the Go 1.25 toolchain.",[214,566,567,568,570,571,570,574,570,577,570,580,583,584,587],{},"No third-party dependencies for the core packages (",[185,569,388],{},", ",[185,572,573],{},"ezz\u002Fbinding",[185,575,576],{},"ezz\u002Fmiddleware",[185,578,579],{},"ezz\u002Fopenapi",[185,581,582],{},"ezz\u002Fauth","). The optional ",[185,585,586],{},"ezz\u002Fauth\u002Fratelimit"," package brings in a Redis client.",[206,589,591],{"id":590},"where-to-go-next","Where to go next",[593,594,595,599,603,606],"card-group",{},[596,597,598],"card",{"icon":19,"title":16,"to":17},"Add the module and check your setup works.",[596,600,602],{"icon":24,"title":601,"to":22},"Quick start","A complete authenticated API with generated docs.",[596,604,605],{"icon":41,"title":38,"to":39},"How typed handlers, responses, and errors work.",[596,607,608],{"icon":69,"title":68,"to":75},"Providers, route rules, roles, and permissions.",[610,611,612],"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":270,"searchDepth":294,"depth":294,"links":614},[615,616,617,618,619],{"id":208,"depth":294,"text":209},{"id":261,"depth":294,"text":262},{"id":537,"depth":294,"text":538},{"id":550,"depth":294,"text":551},{"id":590,"depth":294,"text":591},"What ezz is, what it does for you, and when it is the right choice.","md",null,{},{"icon":14},{"title":11,"description":620},"n0IQgdLTHAIM_37WF5NLg4OQS6SIzJlLrDrMOh_iykY",[622,628],{"title":16,"path":17,"stem":18,"description":629,"icon":19,"children":-1},"Add ezz to a Go module and verify it serves a request.",1784970045270]