[{"data":1,"prerenderedAt":1694},["ShallowReactive",2],{"navigation_docs":3,"-core-errors":172,"-core-errors-surround":1689},[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":58,"body":174,"description":1682,"extension":1683,"links":1684,"meta":1685,"navigation":1686,"path":59,"seo":1687,"stem":60,"__hash__":1688},"docs\u002F2.core\u002F6.errors.md",{"type":175,"value":176,"toc":1672},"minimark",[177,190,195,444,447,516,520,619,659,669,673,679,758,772,776,824,838,855,859,865,920,924,936,944,956,1297,1300,1304,1307,1646,1649,1653,1668],[178,179,180,181,185,186,189],"p",{},"Return an error from a handler and ezz writes the response. If the error is an ",[182,183,184],"code",{},"*ezz.HTTPError",", its status and message are used. Anything else becomes a ",[182,187,188],{},"500"," with a generic message, so an internal failure never leaks its text to the caller.",[191,192,194],"h2",{"id":193},"return-a-typed-error","Return a typed error",[196,197,202],"pre",{"className":198,"code":199,"language":200,"meta":201,"style":201},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","app.GET(\"\u002Fusers\u002F{id}\", ezz.H(func(ctx *ezz.Context, req GetUserRequest) (*User, error) {\n    user, err := store.Find(ctx, req.ID)\n    if errors.Is(err, ErrNotFound) {\n        return nil, ezz.NotFound(\"user not found\")\n    }\n    if err != nil {\n        return nil, err          \u002F\u002F 500, message hidden\n    }\n    return user, nil\n}))\n","go","",[182,203,204,290,328,357,384,390,405,419,424,438],{"__ignoreMap":201},[205,206,209,213,217,221,224,227,231,233,236,239,241,244,247,251,254,258,260,262,264,267,270,273,276,279,281,285,287],"span",{"class":207,"line":208},"line",1,[205,210,212],{"class":211},"sTEyZ","app",[205,214,216],{"class":215},"sMK4o",".",[205,218,220],{"class":219},"s2Zo4","GET",[205,222,223],{"class":215},"(",[205,225,226],{"class":215},"\"",[205,228,230],{"class":229},"sfazB","\u002Fusers\u002F{id}",[205,232,226],{"class":215},[205,234,235],{"class":215},",",[205,237,238],{"class":211}," ezz",[205,240,216],{"class":215},[205,242,243],{"class":219},"H",[205,245,246],{"class":215},"(func(",[205,248,250],{"class":249},"sHdIc","ctx",[205,252,253],{"class":215}," *",[205,255,257],{"class":256},"sBMFI","ezz",[205,259,216],{"class":215},[205,261,53],{"class":256},[205,263,235],{"class":215},[205,265,266],{"class":249}," req",[205,268,269],{"class":256}," GetUserRequest",[205,271,272],{"class":215},")",[205,274,275],{"class":215}," (*",[205,277,278],{"class":256},"User",[205,280,235],{"class":215},[205,282,284],{"class":283},"spNyl"," error",[205,286,272],{"class":215},[205,288,289],{"class":215}," {\n",[205,291,293,296,298,301,304,307,309,312,314,316,318,320,322,325],{"class":207,"line":292},2,[205,294,295],{"class":211},"    user",[205,297,235],{"class":215},[205,299,300],{"class":211}," err ",[205,302,303],{"class":215},":=",[205,305,306],{"class":211}," store",[205,308,216],{"class":215},[205,310,311],{"class":219},"Find",[205,313,223],{"class":215},[205,315,250],{"class":211},[205,317,235],{"class":215},[205,319,266],{"class":211},[205,321,216],{"class":215},[205,323,324],{"class":211},"ID",[205,326,327],{"class":215},")\n",[205,329,331,335,338,340,343,345,348,350,353,355],{"class":207,"line":330},3,[205,332,334],{"class":333},"s7zQu","    if",[205,336,337],{"class":211}," errors",[205,339,216],{"class":215},[205,341,342],{"class":219},"Is",[205,344,223],{"class":215},[205,346,347],{"class":211},"err",[205,349,235],{"class":215},[205,351,352],{"class":211}," ErrNotFound",[205,354,272],{"class":215},[205,356,289],{"class":215},[205,358,360,363,366,368,370,373,375,377,380,382],{"class":207,"line":359},4,[205,361,362],{"class":333},"        return",[205,364,365],{"class":215}," nil,",[205,367,238],{"class":211},[205,369,216],{"class":215},[205,371,372],{"class":219},"NotFound",[205,374,223],{"class":215},[205,376,226],{"class":215},[205,378,379],{"class":229},"user not found",[205,381,226],{"class":215},[205,383,327],{"class":215},[205,385,387],{"class":207,"line":386},5,[205,388,389],{"class":215},"    }\n",[205,391,393,395,397,400,403],{"class":207,"line":392},6,[205,394,334],{"class":333},[205,396,300],{"class":211},[205,398,399],{"class":215},"!=",[205,401,402],{"class":215}," nil",[205,404,289],{"class":215},[205,406,408,410,412,415],{"class":207,"line":407},7,[205,409,362],{"class":333},[205,411,365],{"class":215},[205,413,414],{"class":211}," err          ",[205,416,418],{"class":417},"sHwdD","\u002F\u002F 500, message hidden\n",[205,420,422],{"class":207,"line":421},8,[205,423,389],{"class":215},[205,425,427,430,433,435],{"class":207,"line":426},9,[205,428,429],{"class":333},"    return",[205,431,432],{"class":211}," user",[205,434,235],{"class":215},[205,436,437],{"class":215}," nil\n",[205,439,441],{"class":207,"line":440},10,[205,442,443],{"class":215},"}))\n",[178,445,446],{},"Every error response has the same shape:",[196,448,452],{"className":449,"code":450,"language":451,"meta":201,"style":201},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"error\": true,\n  \"message\": \"user not found\",\n  \"status\": 404\n}\n","json",[182,453,454,459,475,496,511],{"__ignoreMap":201},[205,455,456],{"class":207,"line":208},[205,457,458],{"class":215},"{\n",[205,460,461,464,467,469,472],{"class":207,"line":292},[205,462,463],{"class":215},"  \"",[205,465,466],{"class":283},"error",[205,468,226],{"class":215},[205,470,471],{"class":215},":",[205,473,474],{"class":215}," true,\n",[205,476,477,479,482,484,486,489,491,493],{"class":207,"line":330},[205,478,463],{"class":215},[205,480,481],{"class":283},"message",[205,483,226],{"class":215},[205,485,471],{"class":215},[205,487,488],{"class":215}," \"",[205,490,379],{"class":229},[205,492,226],{"class":215},[205,494,495],{"class":215},",\n",[205,497,498,500,503,505,507],{"class":207,"line":359},[205,499,463],{"class":215},[205,501,502],{"class":283},"status",[205,504,226],{"class":215},[205,506,471],{"class":215},[205,508,510],{"class":509},"sbssI"," 404\n",[205,512,513],{"class":207,"line":386},[205,514,515],{"class":215},"}\n",[191,517,519],{"id":518},"constructors","Constructors",[521,522,523,536],"table",{},[524,525,526],"thead",{},[527,528,529,533],"tr",{},[530,531,532],"th",{},"Constructor",[530,534,535],{},"Status",[537,538,539,550,560,570,580,590,600,609],"tbody",{},[527,540,541,547],{},[542,543,544],"td",{},[182,545,546],{},"ezz.BadRequest(msg)",[542,548,549],{},"400",[527,551,552,557],{},[542,553,554],{},[182,555,556],{},"ezz.Unauthorized(msg)",[542,558,559],{},"401",[527,561,562,567],{},[542,563,564],{},[182,565,566],{},"ezz.Forbidden(msg)",[542,568,569],{},"403",[527,571,572,577],{},[542,573,574],{},[182,575,576],{},"ezz.NotFound(msg)",[542,578,579],{},"404",[527,581,582,587],{},[542,583,584],{},[182,585,586],{},"ezz.Conflict(msg)",[542,588,589],{},"409",[527,591,592,597],{},[542,593,594],{},[182,595,596],{},"ezz.UnprocessableEntity(msg)",[542,598,599],{},"422",[527,601,602,607],{},[542,603,604],{},[182,605,606],{},"ezz.InternalServerError(msg)",[542,608,188],{},[527,610,611,616],{},[542,612,613],{},[182,614,615],{},"ezz.NewHTTPError(status, msg)",[542,617,618],{},"Anything else",[196,620,622],{"className":198,"code":621,"language":200,"meta":201,"style":201},"return nil, ezz.NewHTTPError(http.StatusTeapot, \"no coffee here\")\n",[182,623,624],{"__ignoreMap":201},[205,625,626,629,631,633,635,638,640,643,645,648,650,652,655,657],{"class":207,"line":208},[205,627,628],{"class":333},"return",[205,630,365],{"class":215},[205,632,238],{"class":211},[205,634,216],{"class":215},[205,636,637],{"class":219},"NewHTTPError",[205,639,223],{"class":215},[205,641,642],{"class":211},"http",[205,644,216],{"class":215},[205,646,647],{"class":211},"StatusTeapot",[205,649,235],{"class":215},[205,651,488],{"class":215},[205,653,654],{"class":229},"no coffee here",[205,656,226],{"class":215},[205,658,327],{"class":215},[178,660,661,662,665,666,216],{},"Two sentinel values are also exported and used by the auth rules: ",[182,663,664],{},"ezz.ErrUnauthorized"," and ",[182,667,668],{},"ezz.ErrForbidden",[191,670,672],{"id":671},"keep-the-cause-without-exposing-it","Keep the cause without exposing it",[178,674,675,678],{},[182,676,677],{},"WithInternal"," attaches the underlying error for your own logging while the client still sees only the public message.",[196,680,682],{"className":198,"code":681,"language":200,"meta":201,"style":201},"if err := payments.Charge(ctx, order); err != nil {\n    return nil, ezz.UnprocessableEntity(\"payment declined\").WithInternal(err)\n}\n",[182,683,684,721,754],{"__ignoreMap":201},[205,685,686,689,691,693,696,698,701,703,705,707,710,713,715,717,719],{"class":207,"line":208},[205,687,688],{"class":333},"if",[205,690,300],{"class":211},[205,692,303],{"class":215},[205,694,695],{"class":211}," payments",[205,697,216],{"class":215},[205,699,700],{"class":219},"Charge",[205,702,223],{"class":215},[205,704,250],{"class":211},[205,706,235],{"class":215},[205,708,709],{"class":211}," order",[205,711,712],{"class":215},");",[205,714,300],{"class":211},[205,716,399],{"class":215},[205,718,402],{"class":215},[205,720,289],{"class":215},[205,722,723,725,727,729,731,734,736,738,741,743,746,748,750,752],{"class":207,"line":292},[205,724,429],{"class":333},[205,726,365],{"class":215},[205,728,238],{"class":211},[205,730,216],{"class":215},[205,732,733],{"class":219},"UnprocessableEntity",[205,735,223],{"class":215},[205,737,226],{"class":215},[205,739,740],{"class":229},"payment declined",[205,742,226],{"class":215},[205,744,745],{"class":215},").",[205,747,677],{"class":219},[205,749,223],{"class":215},[205,751,347],{"class":211},[205,753,327],{"class":215},[205,755,756],{"class":207,"line":330},[205,757,515],{"class":215},[178,759,760,761,764,765,768,769,216],{},"The wrapped error shows up in ",[182,762,763],{},"err.Error()"," as ",[182,766,767],{},"\"payment declined: \u003Ccause>\"",", which is what your logging middleware sees, while the response body carries just ",[182,770,771],{},"\"payment declined\"",[191,773,775],{"id":774},"know-which-layer-produced-the-status","Know which layer produced the status",[521,777,778,787],{},[524,779,780],{},[527,781,782,784],{},[530,783,535],{},[530,785,786],{},"Produced by",[537,788,789,796,803,810,817],{},[527,790,791,793],{},[542,792,549],{},[542,794,795],{},"Binding failure or validation failure, before the handler runs",[527,797,798,800],{},[542,799,559],{},[542,801,802],{},"No credentials, or the auth provider rejected them",[527,804,805,807],{},[542,806,569],{},[542,808,809],{},"Authenticated, but the route's role or permission rule said no",[527,811,812,814],{},[542,813,188],{},[542,815,816],{},"An authorization resolver failed, or the handler returned a non-HTTP error",[527,818,819,821],{},[542,820,188],{},[542,822,823],{},"A panic, caught by the recovery middleware",[178,825,826,827,830,831,834,835,216],{},"Auth failures are written by the app before your handler is reached, with the same JSON shape and the messages ",[182,828,829],{},"Unauthorized",", ",[182,832,833],{},"Forbidden",", and ",[182,836,837],{},"Authorization failed",[839,840,841,842,844,845,847,848,850,851,216],"note",{},"A resolver failure deliberately produces ",[182,843,188],{},", not ",[182,846,569],{},". If your permission store is down, the request has not been denied, it is unknown, and a ",[182,849,569],{}," would tell the caller something false. See ",[852,853,854],"a",{"href":90},"Roles and permissions",[191,856,858],{"id":857},"write-an-error-response-directly","Write an error response directly",[178,860,861,864],{},[182,862,863],{},"ctx.Error"," does the same mapping if you want to send an error without returning one:",[196,866,868],{"className":198,"code":867,"language":200,"meta":201,"style":201},"if !ok {\n    return nil, ctx.Error(ezz.Forbidden(\"not your document\"))\n}\n",[182,869,870,882,916],{"__ignoreMap":201},[205,871,872,874,877,880],{"class":207,"line":208},[205,873,688],{"class":333},[205,875,876],{"class":215}," !",[205,878,879],{"class":211},"ok ",[205,881,458],{"class":215},[205,883,884,886,888,891,893,896,898,900,902,904,906,908,911,913],{"class":207,"line":292},[205,885,429],{"class":333},[205,887,365],{"class":215},[205,889,890],{"class":211}," ctx",[205,892,216],{"class":215},[205,894,895],{"class":219},"Error",[205,897,223],{"class":215},[205,899,257],{"class":211},[205,901,216],{"class":215},[205,903,833],{"class":219},[205,905,223],{"class":215},[205,907,226],{"class":215},[205,909,910],{"class":229},"not your document",[205,912,226],{"class":215},[205,914,915],{"class":215},"))\n",[205,917,918],{"class":207,"line":330},[205,919,515],{"class":215},[191,921,923],{"id":922},"handle-panics","Handle panics",[178,925,926,929,930,933,934,216],{},[182,927,928],{},"ezz.New()"," installs ",[182,931,932],{},"Recovery",", which logs the panic with the method and path and replies ",[182,935,188],{},[196,937,942],{"className":938,"code":940,"language":941},[939],"language-text","level=ERROR msg=\"Panic recovered\" error=\"runtime error: index out of range [3]\" method=GET path=\u002Fusers\u002F42\n","text",[182,943,940],{"__ignoreMap":201},[945,946,947,948,951,952,955],"warning",{},"The recovery response is ",[182,949,950],{},"text\u002Fplain"," (",[182,953,954],{},"Internal Server Error","), not the JSON error body used elsewhere. If your clients require JSON on every path, install your own recovery middleware instead of relying on the default.",[196,957,959],{"className":198,"code":958,"language":200,"meta":201,"style":201},"func JSONRecovery(logger *slog.Logger) ezz.Middleware {\n    return func(next http.Handler) http.Handler {\n        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n            defer func() {\n                if v := recover(); v != nil {\n                    logger.Error(\"panic\", \"value\", v, \"path\", r.URL.Path)\n                    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n                    w.WriteHeader(http.StatusInternalServerError)\n                    _, _ = w.Write([]byte(`{\"error\":true,\"message\":\"internal server error\",\"status\":500}`))\n                }\n            }()\n            next.ServeHTTP(w, r)\n        })\n    }\n}\n",[182,960,961,994,1022,1063,1073,1097,1154,1190,1210,1249,1254,1260,1281,1287,1292],{"__ignoreMap":201},[205,962,963,966,969,971,974,976,979,981,984,986,988,990,992],{"class":207,"line":208},[205,964,965],{"class":215},"func",[205,967,968],{"class":219}," JSONRecovery",[205,970,223],{"class":215},[205,972,973],{"class":249},"logger",[205,975,253],{"class":215},[205,977,978],{"class":256},"slog",[205,980,216],{"class":215},[205,982,983],{"class":256},"Logger",[205,985,272],{"class":215},[205,987,238],{"class":256},[205,989,216],{"class":215},[205,991,63],{"class":256},[205,993,289],{"class":215},[205,995,996,998,1001,1004,1007,1009,1012,1014,1016,1018,1020],{"class":207,"line":292},[205,997,429],{"class":333},[205,999,1000],{"class":215}," func(",[205,1002,1003],{"class":249},"next",[205,1005,1006],{"class":256}," http",[205,1008,216],{"class":215},[205,1010,1011],{"class":256},"Handler",[205,1013,272],{"class":215},[205,1015,1006],{"class":256},[205,1017,216],{"class":215},[205,1019,1011],{"class":256},[205,1021,289],{"class":215},[205,1023,1024,1026,1028,1030,1033,1035,1038,1040,1042,1045,1047,1050,1052,1054,1056,1059,1061],{"class":207,"line":330},[205,1025,362],{"class":333},[205,1027,1006],{"class":211},[205,1029,216],{"class":215},[205,1031,1032],{"class":219},"HandlerFunc",[205,1034,246],{"class":215},[205,1036,1037],{"class":249},"w",[205,1039,1006],{"class":256},[205,1041,216],{"class":215},[205,1043,1044],{"class":256},"ResponseWriter",[205,1046,235],{"class":215},[205,1048,1049],{"class":249}," r",[205,1051,253],{"class":215},[205,1053,642],{"class":256},[205,1055,216],{"class":215},[205,1057,1058],{"class":256},"Request",[205,1060,272],{"class":215},[205,1062,289],{"class":215},[205,1064,1065,1068,1071],{"class":207,"line":359},[205,1066,1067],{"class":333},"            defer",[205,1069,1070],{"class":215}," func()",[205,1072,289],{"class":215},[205,1074,1075,1078,1081,1083,1086,1089,1091,1093,1095],{"class":207,"line":386},[205,1076,1077],{"class":333},"                if",[205,1079,1080],{"class":211}," v ",[205,1082,303],{"class":215},[205,1084,1085],{"class":219}," recover",[205,1087,1088],{"class":215},"();",[205,1090,1080],{"class":211},[205,1092,399],{"class":215},[205,1094,402],{"class":215},[205,1096,289],{"class":215},[205,1098,1099,1102,1104,1106,1108,1110,1113,1115,1117,1119,1122,1124,1126,1129,1131,1133,1136,1138,1140,1142,1144,1147,1149,1152],{"class":207,"line":392},[205,1100,1101],{"class":211},"                    logger",[205,1103,216],{"class":215},[205,1105,895],{"class":219},[205,1107,223],{"class":215},[205,1109,226],{"class":215},[205,1111,1112],{"class":229},"panic",[205,1114,226],{"class":215},[205,1116,235],{"class":215},[205,1118,488],{"class":215},[205,1120,1121],{"class":229},"value",[205,1123,226],{"class":215},[205,1125,235],{"class":215},[205,1127,1128],{"class":211}," v",[205,1130,235],{"class":215},[205,1132,488],{"class":215},[205,1134,1135],{"class":229},"path",[205,1137,226],{"class":215},[205,1139,235],{"class":215},[205,1141,1049],{"class":211},[205,1143,216],{"class":215},[205,1145,1146],{"class":211},"URL",[205,1148,216],{"class":215},[205,1150,1151],{"class":211},"Path",[205,1153,327],{"class":215},[205,1155,1156,1159,1161,1164,1167,1170,1172,1174,1177,1179,1181,1183,1186,1188],{"class":207,"line":407},[205,1157,1158],{"class":211},"                    w",[205,1160,216],{"class":215},[205,1162,1163],{"class":219},"Header",[205,1165,1166],{"class":215},"().",[205,1168,1169],{"class":219},"Set",[205,1171,223],{"class":215},[205,1173,226],{"class":215},[205,1175,1176],{"class":229},"Content-Type",[205,1178,226],{"class":215},[205,1180,235],{"class":215},[205,1182,488],{"class":215},[205,1184,1185],{"class":229},"application\u002Fjson",[205,1187,226],{"class":215},[205,1189,327],{"class":215},[205,1191,1192,1194,1196,1199,1201,1203,1205,1208],{"class":207,"line":421},[205,1193,1158],{"class":211},[205,1195,216],{"class":215},[205,1197,1198],{"class":219},"WriteHeader",[205,1200,223],{"class":215},[205,1202,642],{"class":211},[205,1204,216],{"class":215},[205,1206,1207],{"class":211},"StatusInternalServerError",[205,1209,327],{"class":215},[205,1211,1212,1215,1217,1220,1223,1226,1228,1231,1234,1237,1239,1242,1245,1247],{"class":207,"line":426},[205,1213,1214],{"class":211},"                    _",[205,1216,235],{"class":215},[205,1218,1219],{"class":211}," _ ",[205,1221,1222],{"class":215},"=",[205,1224,1225],{"class":211}," w",[205,1227,216],{"class":215},[205,1229,1230],{"class":219},"Write",[205,1232,1233],{"class":215},"([]",[205,1235,1236],{"class":283},"byte",[205,1238,223],{"class":215},[205,1240,1241],{"class":215},"`",[205,1243,1244],{"class":229},"{\"error\":true,\"message\":\"internal server error\",\"status\":500}",[205,1246,1241],{"class":215},[205,1248,915],{"class":215},[205,1250,1251],{"class":207,"line":440},[205,1252,1253],{"class":215},"                }\n",[205,1255,1257],{"class":207,"line":1256},11,[205,1258,1259],{"class":215},"            }()\n",[205,1261,1263,1266,1268,1271,1273,1275,1277,1279],{"class":207,"line":1262},12,[205,1264,1265],{"class":211},"            next",[205,1267,216],{"class":215},[205,1269,1270],{"class":219},"ServeHTTP",[205,1272,223],{"class":215},[205,1274,1037],{"class":211},[205,1276,235],{"class":215},[205,1278,1049],{"class":211},[205,1280,327],{"class":215},[205,1282,1284],{"class":207,"line":1283},13,[205,1285,1286],{"class":215},"        })\n",[205,1288,1290],{"class":207,"line":1289},14,[205,1291,389],{"class":215},[205,1293,1295],{"class":207,"line":1294},15,[205,1296,515],{"class":215},[178,1298,1299],{},"Note that a panic after the response has started writing cannot change the status; the connection is simply closed mid-body.",[191,1301,1303],{"id":1302},"centralise-error-mapping","Centralise error mapping",[178,1305,1306],{},"For a large service, translate domain errors once instead of in every handler:",[196,1308,1310],{"className":198,"code":1309,"language":200,"meta":201,"style":201},"func httpError(err error) error {\n    switch {\n    case err == nil:\n        return nil\n    case errors.Is(err, ErrNotFound):\n        return ezz.NotFound(\"not found\")\n    case errors.Is(err, ErrConflict):\n        return ezz.Conflict(\"already exists\")\n    case errors.Is(err, ErrPermission):\n        return ezz.Forbidden(\"not allowed\")\n    default:\n        return ezz.InternalServerError(\"internal error\").WithInternal(err)\n    }\n}\n\napp.GET(\"\u002Fusers\u002F{id}\", ezz.H(func(ctx *ezz.Context, req GetUserRequest) (*User, error) {\n    user, err := store.Find(ctx, req.ID)\n    return user, httpError(err)\n}))\n",[182,1311,1312,1331,1338,1351,1357,1378,1399,1420,1442,1463,1484,1492,1522,1526,1530,1536,1593,1624,1641],{"__ignoreMap":201},[205,1313,1314,1316,1319,1321,1323,1325,1327,1329],{"class":207,"line":208},[205,1315,965],{"class":215},[205,1317,1318],{"class":219}," httpError",[205,1320,223],{"class":215},[205,1322,347],{"class":249},[205,1324,284],{"class":283},[205,1326,272],{"class":215},[205,1328,284],{"class":283},[205,1330,289],{"class":215},[205,1332,1333,1336],{"class":207,"line":292},[205,1334,1335],{"class":333},"    switch",[205,1337,289],{"class":215},[205,1339,1340,1343,1345,1348],{"class":207,"line":330},[205,1341,1342],{"class":333},"    case",[205,1344,300],{"class":211},[205,1346,1347],{"class":215},"==",[205,1349,1350],{"class":215}," nil:\n",[205,1352,1353,1355],{"class":207,"line":359},[205,1354,362],{"class":333},[205,1356,437],{"class":215},[205,1358,1359,1361,1363,1365,1367,1369,1371,1373,1375],{"class":207,"line":386},[205,1360,1342],{"class":333},[205,1362,337],{"class":211},[205,1364,216],{"class":215},[205,1366,342],{"class":219},[205,1368,223],{"class":215},[205,1370,347],{"class":211},[205,1372,235],{"class":215},[205,1374,352],{"class":211},[205,1376,1377],{"class":215},"):\n",[205,1379,1380,1382,1384,1386,1388,1390,1392,1395,1397],{"class":207,"line":392},[205,1381,362],{"class":333},[205,1383,238],{"class":211},[205,1385,216],{"class":215},[205,1387,372],{"class":219},[205,1389,223],{"class":215},[205,1391,226],{"class":215},[205,1393,1394],{"class":229},"not found",[205,1396,226],{"class":215},[205,1398,327],{"class":215},[205,1400,1401,1403,1405,1407,1409,1411,1413,1415,1418],{"class":207,"line":407},[205,1402,1342],{"class":333},[205,1404,337],{"class":211},[205,1406,216],{"class":215},[205,1408,342],{"class":219},[205,1410,223],{"class":215},[205,1412,347],{"class":211},[205,1414,235],{"class":215},[205,1416,1417],{"class":211}," ErrConflict",[205,1419,1377],{"class":215},[205,1421,1422,1424,1426,1428,1431,1433,1435,1438,1440],{"class":207,"line":421},[205,1423,362],{"class":333},[205,1425,238],{"class":211},[205,1427,216],{"class":215},[205,1429,1430],{"class":219},"Conflict",[205,1432,223],{"class":215},[205,1434,226],{"class":215},[205,1436,1437],{"class":229},"already exists",[205,1439,226],{"class":215},[205,1441,327],{"class":215},[205,1443,1444,1446,1448,1450,1452,1454,1456,1458,1461],{"class":207,"line":426},[205,1445,1342],{"class":333},[205,1447,337],{"class":211},[205,1449,216],{"class":215},[205,1451,342],{"class":219},[205,1453,223],{"class":215},[205,1455,347],{"class":211},[205,1457,235],{"class":215},[205,1459,1460],{"class":211}," ErrPermission",[205,1462,1377],{"class":215},[205,1464,1465,1467,1469,1471,1473,1475,1477,1480,1482],{"class":207,"line":440},[205,1466,362],{"class":333},[205,1468,238],{"class":211},[205,1470,216],{"class":215},[205,1472,833],{"class":219},[205,1474,223],{"class":215},[205,1476,226],{"class":215},[205,1478,1479],{"class":229},"not allowed",[205,1481,226],{"class":215},[205,1483,327],{"class":215},[205,1485,1486,1489],{"class":207,"line":1256},[205,1487,1488],{"class":333},"    default",[205,1490,1491],{"class":215},":\n",[205,1493,1494,1496,1498,1500,1503,1505,1507,1510,1512,1514,1516,1518,1520],{"class":207,"line":1262},[205,1495,362],{"class":333},[205,1497,238],{"class":211},[205,1499,216],{"class":215},[205,1501,1502],{"class":219},"InternalServerError",[205,1504,223],{"class":215},[205,1506,226],{"class":215},[205,1508,1509],{"class":229},"internal error",[205,1511,226],{"class":215},[205,1513,745],{"class":215},[205,1515,677],{"class":219},[205,1517,223],{"class":215},[205,1519,347],{"class":211},[205,1521,327],{"class":215},[205,1523,1524],{"class":207,"line":1283},[205,1525,389],{"class":215},[205,1527,1528],{"class":207,"line":1289},[205,1529,515],{"class":215},[205,1531,1532],{"class":207,"line":1294},[205,1533,1535],{"emptyLinePlaceholder":1534},true,"\n",[205,1537,1539,1541,1543,1545,1547,1549,1551,1553,1555,1557,1559,1561,1563,1565,1567,1569,1571,1573,1575,1577,1579,1581,1583,1585,1587,1589,1591],{"class":207,"line":1538},16,[205,1540,212],{"class":211},[205,1542,216],{"class":215},[205,1544,220],{"class":219},[205,1546,223],{"class":215},[205,1548,226],{"class":215},[205,1550,230],{"class":229},[205,1552,226],{"class":215},[205,1554,235],{"class":215},[205,1556,238],{"class":211},[205,1558,216],{"class":215},[205,1560,243],{"class":219},[205,1562,246],{"class":215},[205,1564,250],{"class":249},[205,1566,253],{"class":215},[205,1568,257],{"class":256},[205,1570,216],{"class":215},[205,1572,53],{"class":256},[205,1574,235],{"class":215},[205,1576,266],{"class":249},[205,1578,269],{"class":256},[205,1580,272],{"class":215},[205,1582,275],{"class":215},[205,1584,278],{"class":256},[205,1586,235],{"class":215},[205,1588,284],{"class":283},[205,1590,272],{"class":215},[205,1592,289],{"class":215},[205,1594,1596,1598,1600,1602,1604,1606,1608,1610,1612,1614,1616,1618,1620,1622],{"class":207,"line":1595},17,[205,1597,295],{"class":211},[205,1599,235],{"class":215},[205,1601,300],{"class":211},[205,1603,303],{"class":215},[205,1605,306],{"class":211},[205,1607,216],{"class":215},[205,1609,311],{"class":219},[205,1611,223],{"class":215},[205,1613,250],{"class":211},[205,1615,235],{"class":215},[205,1617,266],{"class":211},[205,1619,216],{"class":215},[205,1621,324],{"class":211},[205,1623,327],{"class":215},[205,1625,1627,1629,1631,1633,1635,1637,1639],{"class":207,"line":1626},18,[205,1628,429],{"class":333},[205,1630,432],{"class":211},[205,1632,235],{"class":215},[205,1634,1318],{"class":219},[205,1636,223],{"class":215},[205,1638,347],{"class":211},[205,1640,327],{"class":215},[205,1642,1644],{"class":207,"line":1643},19,[205,1645,443],{"class":215},[178,1647,1648],{},"Returning a non-nil value alongside an error is safe: the error wins and the value is discarded.",[191,1650,1652],{"id":1651},"next-steps","Next steps",[1654,1655,1656,1662],"ul",{},[1657,1658,1659,1661],"li",{},[852,1660,63],{"href":64}," for recovery, logging, and the rest of the chain.",[1657,1663,1664,1667],{},[852,1665,1666],{"href":80},"Auth rules"," for where 401 and 403 come from.",[1669,1670,1671],"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 .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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":201,"searchDepth":292,"depth":292,"links":1673},[1674,1675,1676,1677,1678,1679,1680,1681],{"id":193,"depth":292,"text":194},{"id":518,"depth":292,"text":519},{"id":671,"depth":292,"text":672},{"id":774,"depth":292,"text":775},{"id":857,"depth":292,"text":858},{"id":922,"depth":292,"text":923},{"id":1302,"depth":292,"text":1303},{"id":1651,"depth":292,"text":1652},"Map Go errors to status codes and control the error body.","md",null,{},{"icon":61},{"title":58,"description":1682},"Jf2gfbikdZ5hw8aUbFHg9n_1t-yLZwRIgYtcpYxbGjs",[1690,1692],{"title":53,"path":54,"stem":55,"description":1691,"icon":56,"children":-1},"Read request data, write responses, stream events, and reach the authenticated user.",{"title":63,"path":64,"stem":65,"description":1693,"icon":66,"children":-1},"Use the built-in middleware, add your own, and understand the order everything runs in.",1784970047281]