[{"data":1,"prerenderedAt":1930},["ShallowReactive",2],{"navigation_docs":3,"-api-docs-openapi":172,"-api-docs-openapi-surround":1925},[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":131,"body":174,"description":1918,"extension":1919,"links":1920,"meta":1921,"navigation":1922,"path":132,"seo":1923,"stem":133,"__hash__":1924},"docs\u002F5.api-docs\u002F1.openapi.md",{"type":175,"value":176,"toc":1907},"minimark",[177,181,186,246,261,302,305,309,312,460,463,563,567,686,694,758,771,775,788,814,833,913,917,935,939,944,1448,1454,1458,1461,1590,1614,1617,1639,1643,1884,1888,1903],[178,179,180],"p",{},"The spec is derived from what you already wrote: handler request and response types, binding tags, validation rules, and route metadata. There is no separate annotation language and no generation step.",[182,183,185],"h2",{"id":184},"serve-the-spec","Serve the spec",[187,188,193],"pre",{"className":189,"code":190,"language":191,"meta":192,"style":192},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fsulv-io\u002Fezz\u002Fopenapi\"\n\nopenapi.SetupDocsEndpoints(app)\n","go","",[194,195,196,216,223],"code",{"__ignoreMap":192},[197,198,201,205,209,213],"span",{"class":199,"line":200},"line",1,[197,202,204],{"class":203},"s7zQu","import",[197,206,208],{"class":207},"sMK4o"," \"",[197,210,212],{"class":211},"sBMFI","github.com\u002Fsulv-io\u002Fezz\u002Fopenapi",[197,214,215],{"class":207},"\"\n",[197,217,219],{"class":199,"line":218},2,[197,220,222],{"emptyLinePlaceholder":221},true,"\n",[197,224,226,230,233,237,240,243],{"class":199,"line":225},3,[197,227,229],{"class":228},"sTEyZ","openapi",[197,231,232],{"class":207},".",[197,234,236],{"class":235},"s2Zo4","SetupDocsEndpoints",[197,238,239],{"class":207},"(",[197,241,242],{"class":228},"app",[197,244,245],{"class":207},")\n",[178,247,248,249,252,253,256,257,260],{},"That registers two public routes: ",[194,250,251],{},"\u002Fopenapi.json"," with the document and ",[194,254,255],{},"\u002Fdocs"," with a ",[258,259,136],"a",{"href":137},". For different paths, call the underlying function:",[187,262,264],{"className":189,"code":263,"language":191,"meta":192,"style":192},"openapi.ServeScalar(app, \"\u002Fapi\u002Fopenapi.json\", \"\u002Fapi\u002Freference\")\n",[194,265,266],{"__ignoreMap":192},[197,267,268,270,272,275,277,279,282,284,288,291,293,295,298,300],{"class":199,"line":200},[197,269,229],{"class":228},[197,271,232],{"class":207},[197,273,274],{"class":235},"ServeScalar",[197,276,239],{"class":207},[197,278,242],{"class":228},[197,280,281],{"class":207},",",[197,283,208],{"class":207},[197,285,287],{"class":286},"sfazB","\u002Fapi\u002Fopenapi.json",[197,289,290],{"class":207},"\"",[197,292,281],{"class":207},[197,294,208],{"class":207},[197,296,297],{"class":286},"\u002Fapi\u002Freference",[197,299,290],{"class":207},[197,301,245],{"class":207},[178,303,304],{},"The document is built per request from the routes registered on the app, so call it wherever you like in your setup; late-registered routes still appear.",[182,306,308],{"id":307},"what-ends-up-in-the-document","What ends up in the document",[178,310,311],{},"For each route:",[313,314,315,328],"table",{},[316,317,318],"thead",{},[319,320,321,325],"tr",{},[322,323,324],"th",{},"Source",[322,326,327],{},"Becomes",[329,330,331,344,355,368,378,396,408,419,430,440,450],"tbody",{},[319,332,333,337],{},[334,335,336],"td",{},"Method and pattern",[334,338,339,340,343],{},"The path item and operation, with ",[194,341,342],{},"{id}"," segments intact",[319,345,346,352],{},[334,347,348,351],{},[194,349,350],{},"path"," tagged fields",[334,353,354],{},"Path parameters, always required",[319,356,357,362],{},[334,358,359,351],{},[194,360,361],{},"query",[334,363,364,365],{},"Query parameters, required when the field validates as ",[194,366,367],{},"required",[319,369,370,375],{},[334,371,372,351],{},[194,373,374],{},"header",[334,376,377],{},"Header parameters",[319,379,380,393],{},[334,381,382,383,386,387,386,390],{},"Request type on ",[194,384,385],{},"POST",", ",[194,388,389],{},"PUT",[194,391,392],{},"PATCH",[334,394,395],{},"A JSON request body schema",[319,397,398,401],{},[334,399,400],{},"Response type",[334,402,403,404,407],{},"The ",[194,405,406],{},"200"," response schema",[319,409,410,416],{},[334,411,412,415],{},[194,413,414],{},"validate"," rules",[334,417,418],{},"Schema constraints, see below",[319,420,421,427],{},[334,422,423,426],{},[194,424,425],{},"description"," tag",[334,428,429],{},"Parameter and property descriptions",[319,431,432,437],{},[334,433,434,426],{},[194,435,436],{},"example",[334,438,439],{},"Parameter and property examples",[319,441,442,447],{},[334,443,444],{},[194,445,446],{},".Tags(...)",[334,448,449],{},"Operation tags, and the grouping in the UI",[319,451,452,457],{},[334,453,454],{},[194,455,456],{},".Description(...)",[334,458,459],{},"Operation description",[178,461,462],{},"Validation rules map onto JSON Schema:",[313,464,465,475],{},[316,466,467],{},[319,468,469,472],{},[322,470,471],{},"Rule",[322,473,474],{},"Schema",[329,476,477,497,514,528,540,552],{},[319,478,479,489],{},[334,480,481,484,485,488],{},[194,482,483],{},"min"," \u002F ",[194,486,487],{},"max"," on strings and arrays",[334,490,491,484,494],{},[194,492,493],{},"minLength",[194,495,496],{},"maxLength",[319,498,499,506],{},[334,500,501,484,503,505],{},[194,502,483],{},[194,504,487],{}," on numbers",[334,507,508,484,511],{},[194,509,510],{},"minimum",[194,512,513],{},"maximum",[319,515,516,521],{},[334,517,518],{},[194,519,520],{},"len",[334,522,523,525,526],{},[194,524,493],{}," and ",[194,527,496],{},[319,529,530,535],{},[334,531,532],{},[194,533,534],{},"email",[334,536,537],{},[194,538,539],{},"format: email",[319,541,542,547],{},[334,543,544],{},[194,545,546],{},"url",[334,548,549],{},[194,550,551],{},"format: uri",[319,553,554,559],{},[334,555,556,426],{},[194,557,558],{},"default",[334,560,561],{},[194,562,558],{},[182,564,566],{"id":565},"document-a-request-type-well","Document a request type well",[187,568,570],{"className":189,"code":569,"language":191,"meta":192,"style":192},"type ListUsersRequest struct {\n    Team   string `path:\"team\" description:\"Team slug\"`\n    Query  string `query:\"q\" description:\"Free text search\" example:\"ada\"`\n    Role   string `query:\"role\" description:\"Filter by role\" example:\"admin\"`\n    Page   int    `query:\"page\" default:\"1\" description:\"1-based page number\"`\n    Limit  int    `query:\"limit\" default:\"25\" validate:\"min=1,max=100\" description:\"Page size\"`\n    Cursor string `header:\"X-Cursor\" description:\"Opaque pagination cursor\"`\n}\n",[194,571,572,586,604,618,633,650,665,680],{"__ignoreMap":192},[197,573,574,577,580,583],{"class":199,"line":200},[197,575,576],{"class":207},"type",[197,578,579],{"class":211}," ListUsersRequest",[197,581,582],{"class":207}," struct",[197,584,585],{"class":207}," {\n",[197,587,588,591,595,598,601],{"class":199,"line":218},[197,589,590],{"class":228},"    Team   ",[197,592,594],{"class":593},"spNyl","string",[197,596,597],{"class":207}," `",[197,599,600],{"class":286},"path:\"team\" description:\"Team slug\"",[197,602,603],{"class":207},"`\n",[197,605,606,609,611,613,616],{"class":199,"line":225},[197,607,608],{"class":228},"    Query  ",[197,610,594],{"class":593},[197,612,597],{"class":207},[197,614,615],{"class":286},"query:\"q\" description:\"Free text search\" example:\"ada\"",[197,617,603],{"class":207},[197,619,621,624,626,628,631],{"class":199,"line":620},4,[197,622,623],{"class":228},"    Role   ",[197,625,594],{"class":593},[197,627,597],{"class":207},[197,629,630],{"class":286},"query:\"role\" description:\"Filter by role\" example:\"admin\"",[197,632,603],{"class":207},[197,634,636,639,642,645,648],{"class":199,"line":635},5,[197,637,638],{"class":228},"    Page   ",[197,640,641],{"class":593},"int",[197,643,644],{"class":207},"    `",[197,646,647],{"class":286},"query:\"page\" default:\"1\" description:\"1-based page number\"",[197,649,603],{"class":207},[197,651,653,656,658,660,663],{"class":199,"line":652},6,[197,654,655],{"class":228},"    Limit  ",[197,657,641],{"class":593},[197,659,644],{"class":207},[197,661,662],{"class":286},"query:\"limit\" default:\"25\" validate:\"min=1,max=100\" description:\"Page size\"",[197,664,603],{"class":207},[197,666,668,671,673,675,678],{"class":199,"line":667},7,[197,669,670],{"class":228},"    Cursor ",[197,672,594],{"class":593},[197,674,597],{"class":207},[197,676,677],{"class":286},"header:\"X-Cursor\" description:\"Opaque pagination cursor\"",[197,679,603],{"class":207},[197,681,683],{"class":199,"line":682},8,[197,684,685],{"class":207},"}\n",[178,687,688,689,525,691,693],{},"The generator reads ",[194,690,425],{},[194,692,436],{}," on response struct fields too, so the same tags improve both directions:",[187,695,697],{"className":189,"code":696,"language":191,"meta":192,"style":192},"type User struct {\n    ID    string `json:\"id\" description:\"Stable user identifier\" example:\"usr_123\"`\n    Email string `json:\"email\" description:\"Primary email\" example:\"ada@example.com\"`\n    Admin bool   `json:\"admin\" description:\"Whether the user has admin rights\"`\n}\n",[194,698,699,710,724,738,754],{"__ignoreMap":192},[197,700,701,703,706,708],{"class":199,"line":200},[197,702,576],{"class":207},[197,704,705],{"class":211}," User",[197,707,582],{"class":207},[197,709,585],{"class":207},[197,711,712,715,717,719,722],{"class":199,"line":218},[197,713,714],{"class":228},"    ID    ",[197,716,594],{"class":593},[197,718,597],{"class":207},[197,720,721],{"class":286},"json:\"id\" description:\"Stable user identifier\" example:\"usr_123\"",[197,723,603],{"class":207},[197,725,726,729,731,733,736],{"class":199,"line":225},[197,727,728],{"class":228},"    Email ",[197,730,594],{"class":593},[197,732,597],{"class":207},[197,734,735],{"class":286},"json:\"email\" description:\"Primary email\" example:\"ada@example.com\"",[197,737,603],{"class":207},[197,739,740,743,746,749,752],{"class":199,"line":620},[197,741,742],{"class":228},"    Admin ",[197,744,745],{"class":593},"bool",[197,747,748],{"class":207},"   `",[197,750,751],{"class":286},"json:\"admin\" description:\"Whether the user has admin rights\"",[197,753,603],{"class":207},[197,755,756],{"class":199,"line":635},[197,757,685],{"class":207},[178,759,760,761,763,764,766,767,770],{},"When no ",[194,762,436],{}," is given, the generator invents one from the field name and type, so ",[194,765,534],{}," fields get an email-looking value and ",[194,768,769],{},"created_at"," gets a timestamp.",[182,772,774],{"id":773},"responses-that-are-always-documented","Responses that are always documented",[178,776,777,778,386,780,783,784,787],{},"Every operation gets ",[194,779,406],{},[194,781,782],{},"400",", and ",[194,785,786],{},"500",", with the standard error body schema. Two more are added conditionally:",[789,790,791,801],"ul",{},[792,793,794,797,798,232],"li",{},[194,795,796],{},"401"," unless the operation's tags include ",[194,799,800],{},"Public",[792,802,803,806,807,810,811,232],{},[194,804,805],{},"403"," when the tags include ",[194,808,809],{},"Admin"," or ",[194,812,813],{},"Management",[178,815,816,817,820,821,386,824,386,827,830,831,232],{},"Security follows the same rule: a ",[194,818,819],{},"bearerAuth"," requirement (",[194,822,823],{},"http",[194,825,826],{},"bearer",[194,828,829],{},"JWT",") is attached to every operation whose tags do not include ",[194,832,800],{},[834,835,836,855],"note",{},[178,837,838,839,841,842,846,847,850,851,854],{},"The security marker is driven by the ",[194,840,800],{}," ",[843,844,845],"strong",{},"tag",", not by the route's auth rule. A route registered with ",[194,848,849],{},".Public()"," but tagged ",[194,852,853],{},"Users"," is still documented as requiring a bearer token. Add the tag when you want the spec to agree:",[187,856,858],{"className":189,"code":857,"language":191,"meta":192,"style":192},"app.GET(\"\u002Fhealth\", health).Public().Tags(\"System\", \"Public\")\n",[194,859,860],{"__ignoreMap":192},[197,861,862,864,866,869,871,873,876,878,880,883,886,888,891,894,896,898,901,903,905,907,909,911],{"class":199,"line":200},[197,863,242],{"class":228},[197,865,232],{"class":207},[197,867,868],{"class":235},"GET",[197,870,239],{"class":207},[197,872,290],{"class":207},[197,874,875],{"class":286},"\u002Fhealth",[197,877,290],{"class":207},[197,879,281],{"class":207},[197,881,882],{"class":228}," health",[197,884,885],{"class":207},").",[197,887,800],{"class":235},[197,889,890],{"class":207},"().",[197,892,893],{"class":235},"Tags",[197,895,239],{"class":207},[197,897,290],{"class":207},[197,899,900],{"class":286},"System",[197,902,290],{"class":207},[197,904,281],{"class":207},[197,906,208],{"class":207},[197,908,800],{"class":286},[197,910,290],{"class":207},[197,912,245],{"class":207},[182,914,916],{"id":915},"metadata-that-is-not-emitted-yet","Metadata that is not emitted yet",[178,918,919,386,922,386,925,783,928,931,932,934],{},[194,920,921],{},".Summary(...)",[194,923,924],{},".OperationID(...)",[194,926,927],{},".Deprecated()",[194,929,930],{},".Response(...)"," are recorded on the route but do not reach the generated document. Operation IDs are generated from the method and path, and summaries are absent. Use ",[194,933,456],{}," for prose that has to appear in the docs, and treat the others as forward-looking.",[182,936,938],{"id":937},"set-the-document-title-and-servers","Set the document title and servers",[178,940,941,943],{},[194,942,236],{}," uses a generator with empty info, which falls back to the title \"API Documentation\" and version \"1.0.0\". To control that, or to add servers and security schemes, build the generator yourself and serve the result:",[187,945,947],{"className":189,"code":946,"language":191,"meta":192,"style":192},"gen := openapi.NewGenerator()\ngen.Info = openapi.Info{\n    Title:       \"Orders API\",\n    Version:     \"2025-07-01\",\n    Description: \"Order management for internal services.\",\n    Contact:     &openapi.Contact{Name: \"Platform team\", Email: \"platform@example.com\"},\n}\ngen.Servers = []openapi.Server{\n    {URL: \"https:\u002F\u002Fapi.example.com\", Description: \"Production\"},\n    {URL: \"https:\u002F\u002Fstaging.api.example.com\", Description: \"Staging\"},\n}\n\nopenapi.AddSecurityScheme(gen, \"apiKey\", openapi.SecurityScheme{\n    Type: \"apiKey\",\n    In:   \"header\",\n    Name: \"X-API-Key\",\n})\n\napp.GET(\"\u002Fopenapi.json\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"application\u002Fjson\")\n    _, _ = w.Write([]byte(openapi.MustJSON(gen.GenerateFromApp(app))))\n})).Public()\n",[194,948,949,968,991,1010,1027,1043,1092,1096,1119,1153,1184,1189,1194,1228,1244,1261,1278,1284,1289,1350,1386,1438],{"__ignoreMap":192},[197,950,951,954,957,960,962,965],{"class":199,"line":200},[197,952,953],{"class":228},"gen ",[197,955,956],{"class":207},":=",[197,958,959],{"class":228}," openapi",[197,961,232],{"class":207},[197,963,964],{"class":235},"NewGenerator",[197,966,967],{"class":207},"()\n",[197,969,970,973,975,978,981,983,985,988],{"class":199,"line":218},[197,971,972],{"class":228},"gen",[197,974,232],{"class":207},[197,976,977],{"class":228},"Info ",[197,979,980],{"class":207},"=",[197,982,959],{"class":211},[197,984,232],{"class":207},[197,986,987],{"class":211},"Info",[197,989,990],{"class":207},"{\n",[197,992,993,996,999,1002,1005,1007],{"class":199,"line":225},[197,994,995],{"class":228},"    Title",[197,997,998],{"class":207},":",[197,1000,1001],{"class":207},"       \"",[197,1003,1004],{"class":286},"Orders API",[197,1006,290],{"class":207},[197,1008,1009],{"class":207},",\n",[197,1011,1012,1015,1017,1020,1023,1025],{"class":199,"line":620},[197,1013,1014],{"class":228},"    Version",[197,1016,998],{"class":207},[197,1018,1019],{"class":207},"     \"",[197,1021,1022],{"class":286},"2025-07-01",[197,1024,290],{"class":207},[197,1026,1009],{"class":207},[197,1028,1029,1032,1034,1036,1039,1041],{"class":199,"line":635},[197,1030,1031],{"class":228},"    Description",[197,1033,998],{"class":207},[197,1035,208],{"class":207},[197,1037,1038],{"class":286},"Order management for internal services.",[197,1040,290],{"class":207},[197,1042,1009],{"class":207},[197,1044,1045,1048,1050,1053,1055,1057,1060,1063,1066,1068,1070,1073,1075,1077,1080,1082,1084,1087,1089],{"class":199,"line":652},[197,1046,1047],{"class":228},"    Contact",[197,1049,998],{"class":207},[197,1051,1052],{"class":207},"     &",[197,1054,229],{"class":211},[197,1056,232],{"class":207},[197,1058,1059],{"class":211},"Contact",[197,1061,1062],{"class":207},"{",[197,1064,1065],{"class":228},"Name",[197,1067,998],{"class":207},[197,1069,208],{"class":207},[197,1071,1072],{"class":286},"Platform team",[197,1074,290],{"class":207},[197,1076,281],{"class":207},[197,1078,1079],{"class":228}," Email",[197,1081,998],{"class":207},[197,1083,208],{"class":207},[197,1085,1086],{"class":286},"platform@example.com",[197,1088,290],{"class":207},[197,1090,1091],{"class":207},"},\n",[197,1093,1094],{"class":199,"line":667},[197,1095,685],{"class":207},[197,1097,1098,1100,1102,1105,1107,1110,1112,1114,1117],{"class":199,"line":682},[197,1099,972],{"class":228},[197,1101,232],{"class":207},[197,1103,1104],{"class":228},"Servers ",[197,1106,980],{"class":207},[197,1108,1109],{"class":207}," []",[197,1111,229],{"class":211},[197,1113,232],{"class":207},[197,1115,1116],{"class":211},"Server",[197,1118,990],{"class":207},[197,1120,1122,1125,1128,1130,1132,1135,1137,1139,1142,1144,1146,1149,1151],{"class":199,"line":1121},9,[197,1123,1124],{"class":207},"    {",[197,1126,1127],{"class":228},"URL",[197,1129,998],{"class":207},[197,1131,208],{"class":207},[197,1133,1134],{"class":286},"https:\u002F\u002Fapi.example.com",[197,1136,290],{"class":207},[197,1138,281],{"class":207},[197,1140,1141],{"class":228}," Description",[197,1143,998],{"class":207},[197,1145,208],{"class":207},[197,1147,1148],{"class":286},"Production",[197,1150,290],{"class":207},[197,1152,1091],{"class":207},[197,1154,1156,1158,1160,1162,1164,1167,1169,1171,1173,1175,1177,1180,1182],{"class":199,"line":1155},10,[197,1157,1124],{"class":207},[197,1159,1127],{"class":228},[197,1161,998],{"class":207},[197,1163,208],{"class":207},[197,1165,1166],{"class":286},"https:\u002F\u002Fstaging.api.example.com",[197,1168,290],{"class":207},[197,1170,281],{"class":207},[197,1172,1141],{"class":228},[197,1174,998],{"class":207},[197,1176,208],{"class":207},[197,1178,1179],{"class":286},"Staging",[197,1181,290],{"class":207},[197,1183,1091],{"class":207},[197,1185,1187],{"class":199,"line":1186},11,[197,1188,685],{"class":207},[197,1190,1192],{"class":199,"line":1191},12,[197,1193,222],{"emptyLinePlaceholder":221},[197,1195,1197,1199,1201,1204,1206,1208,1210,1212,1215,1217,1219,1221,1223,1226],{"class":199,"line":1196},13,[197,1198,229],{"class":228},[197,1200,232],{"class":207},[197,1202,1203],{"class":235},"AddSecurityScheme",[197,1205,239],{"class":207},[197,1207,972],{"class":228},[197,1209,281],{"class":207},[197,1211,208],{"class":207},[197,1213,1214],{"class":286},"apiKey",[197,1216,290],{"class":207},[197,1218,281],{"class":207},[197,1220,959],{"class":211},[197,1222,232],{"class":207},[197,1224,1225],{"class":211},"SecurityScheme",[197,1227,990],{"class":207},[197,1229,1231,1234,1236,1238,1240,1242],{"class":199,"line":1230},14,[197,1232,1233],{"class":228},"    Type",[197,1235,998],{"class":207},[197,1237,208],{"class":207},[197,1239,1214],{"class":286},[197,1241,290],{"class":207},[197,1243,1009],{"class":207},[197,1245,1247,1250,1252,1255,1257,1259],{"class":199,"line":1246},15,[197,1248,1249],{"class":228},"    In",[197,1251,998],{"class":207},[197,1253,1254],{"class":207},"   \"",[197,1256,374],{"class":286},[197,1258,290],{"class":207},[197,1260,1009],{"class":207},[197,1262,1264,1267,1269,1271,1274,1276],{"class":199,"line":1263},16,[197,1265,1266],{"class":228},"    Name",[197,1268,998],{"class":207},[197,1270,208],{"class":207},[197,1272,1273],{"class":286},"X-API-Key",[197,1275,290],{"class":207},[197,1277,1009],{"class":207},[197,1279,1281],{"class":199,"line":1280},17,[197,1282,1283],{"class":207},"})\n",[197,1285,1287],{"class":199,"line":1286},18,[197,1288,222],{"emptyLinePlaceholder":221},[197,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1311,1313,1316,1319,1323,1325,1327,1330,1332,1335,1338,1340,1342,1345,1348],{"class":199,"line":1291},19,[197,1293,242],{"class":228},[197,1295,232],{"class":207},[197,1297,868],{"class":235},[197,1299,239],{"class":207},[197,1301,290],{"class":207},[197,1303,251],{"class":286},[197,1305,290],{"class":207},[197,1307,281],{"class":207},[197,1309,1310],{"class":228}," http",[197,1312,232],{"class":207},[197,1314,1315],{"class":235},"HandlerFunc",[197,1317,1318],{"class":207},"(func(",[197,1320,1322],{"class":1321},"sHdIc","w",[197,1324,1310],{"class":211},[197,1326,232],{"class":207},[197,1328,1329],{"class":211},"ResponseWriter",[197,1331,281],{"class":207},[197,1333,1334],{"class":1321}," r",[197,1336,1337],{"class":207}," *",[197,1339,823],{"class":211},[197,1341,232],{"class":207},[197,1343,1344],{"class":211},"Request",[197,1346,1347],{"class":207},")",[197,1349,585],{"class":207},[197,1351,1353,1356,1358,1361,1363,1366,1368,1370,1373,1375,1377,1379,1382,1384],{"class":199,"line":1352},20,[197,1354,1355],{"class":228},"    w",[197,1357,232],{"class":207},[197,1359,1360],{"class":235},"Header",[197,1362,890],{"class":207},[197,1364,1365],{"class":235},"Set",[197,1367,239],{"class":207},[197,1369,290],{"class":207},[197,1371,1372],{"class":286},"Content-Type",[197,1374,290],{"class":207},[197,1376,281],{"class":207},[197,1378,208],{"class":207},[197,1380,1381],{"class":286},"application\u002Fjson",[197,1383,290],{"class":207},[197,1385,245],{"class":207},[197,1387,1389,1392,1394,1397,1399,1402,1404,1407,1410,1413,1415,1417,1419,1422,1424,1426,1428,1431,1433,1435],{"class":199,"line":1388},21,[197,1390,1391],{"class":228},"    _",[197,1393,281],{"class":207},[197,1395,1396],{"class":228}," _ ",[197,1398,980],{"class":207},[197,1400,1401],{"class":228}," w",[197,1403,232],{"class":207},[197,1405,1406],{"class":235},"Write",[197,1408,1409],{"class":207},"([]",[197,1411,1412],{"class":593},"byte",[197,1414,239],{"class":207},[197,1416,229],{"class":228},[197,1418,232],{"class":207},[197,1420,1421],{"class":235},"MustJSON",[197,1423,239],{"class":207},[197,1425,972],{"class":228},[197,1427,232],{"class":207},[197,1429,1430],{"class":235},"GenerateFromApp",[197,1432,239],{"class":207},[197,1434,242],{"class":228},[197,1436,1437],{"class":207},"))))\n",[197,1439,1441,1444,1446],{"class":199,"line":1440},22,[197,1442,1443],{"class":207},"})).",[197,1445,800],{"class":235},[197,1447,967],{"class":207},[178,1449,1450,1451,232],{},"Then point the UI at your path with ",[194,1452,1453],{},"openapi.ServeScalar(app, \"\u002Fopenapi.json\", \"\u002Fdocs\")",[182,1455,1457],{"id":1456},"export-the-spec-to-a-file","Export the spec to a file",[178,1459,1460],{},"Useful for client generation or for checking the spec into review:",[187,1462,1464],{"className":189,"code":1463,"language":191,"meta":192,"style":192},"\u002F\u002Fgo:build tools\n\npackage main\n\nfunc main() {\n    app := buildApp()   \u002F\u002F the same function your server uses\n    spec := openapi.NewGenerator().GenerateFromApp(app)\n    os.WriteFile(\"openapi.json\", []byte(openapi.MustJSON(spec)), 0o644)\n}\n",[194,1465,1466,1472,1476,1484,1488,1501,1516,1539,1586],{"__ignoreMap":192},[197,1467,1468],{"class":199,"line":200},[197,1469,1471],{"class":1470},"sHwdD","\u002F\u002Fgo:build tools\n",[197,1473,1474],{"class":199,"line":218},[197,1475,222],{"emptyLinePlaceholder":221},[197,1477,1478,1481],{"class":199,"line":225},[197,1479,1480],{"class":207},"package",[197,1482,1483],{"class":211}," main\n",[197,1485,1486],{"class":199,"line":620},[197,1487,222],{"emptyLinePlaceholder":221},[197,1489,1490,1493,1496,1499],{"class":199,"line":635},[197,1491,1492],{"class":207},"func",[197,1494,1495],{"class":235}," main",[197,1497,1498],{"class":207},"()",[197,1500,585],{"class":207},[197,1502,1503,1506,1508,1511,1513],{"class":199,"line":652},[197,1504,1505],{"class":228},"    app ",[197,1507,956],{"class":207},[197,1509,1510],{"class":235}," buildApp",[197,1512,1498],{"class":207},[197,1514,1515],{"class":1470},"   \u002F\u002F the same function your server uses\n",[197,1517,1518,1521,1523,1525,1527,1529,1531,1533,1535,1537],{"class":199,"line":667},[197,1519,1520],{"class":228},"    spec ",[197,1522,956],{"class":207},[197,1524,959],{"class":228},[197,1526,232],{"class":207},[197,1528,964],{"class":235},[197,1530,890],{"class":207},[197,1532,1430],{"class":235},[197,1534,239],{"class":207},[197,1536,242],{"class":228},[197,1538,245],{"class":207},[197,1540,1541,1544,1546,1549,1551,1553,1556,1558,1560,1562,1564,1566,1568,1570,1572,1574,1577,1580,1584],{"class":199,"line":682},[197,1542,1543],{"class":228},"    os",[197,1545,232],{"class":207},[197,1547,1548],{"class":235},"WriteFile",[197,1550,239],{"class":207},[197,1552,290],{"class":207},[197,1554,1555],{"class":286},"openapi.json",[197,1557,290],{"class":207},[197,1559,281],{"class":207},[197,1561,1109],{"class":207},[197,1563,1412],{"class":593},[197,1565,239],{"class":207},[197,1567,229],{"class":228},[197,1569,232],{"class":207},[197,1571,1421],{"class":235},[197,1573,239],{"class":207},[197,1575,1576],{"class":228},"spec",[197,1578,1579],{"class":207},")),",[197,1581,1583],{"class":1582},"sbssI"," 0o644",[197,1585,245],{"class":207},[197,1587,1588],{"class":199,"line":1121},[197,1589,685],{"class":207},[187,1591,1596],{"className":1592,"code":1593,"filename":1594,"language":1595,"meta":192,"style":192},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go run -tags tools .\u002Fcmd\u002Fspec\n","Terminal","bash",[194,1597,1598],{"__ignoreMap":192},[197,1599,1600,1602,1605,1608,1611],{"class":199,"line":200},[197,1601,191],{"class":211},[197,1603,1604],{"class":286}," run",[197,1606,1607],{"class":286}," -tags",[197,1609,1610],{"class":286}," tools",[197,1612,1613],{"class":286}," .\u002Fcmd\u002Fspec\n",[178,1615,1616],{},"Keeping the generated file under version control makes an accidental breaking change visible in a diff. It also feeds client generators:",[187,1618,1620],{"className":1592,"code":1619,"filename":1594,"language":1595,"meta":192,"style":192},"npx openapi-typescript openapi.json -o client\u002Ftypes.ts\n",[194,1621,1622],{"__ignoreMap":192},[197,1623,1624,1627,1630,1633,1636],{"class":199,"line":200},[197,1625,1626],{"class":211},"npx",[197,1628,1629],{"class":286}," openapi-typescript",[197,1631,1632],{"class":286}," openapi.json",[197,1634,1635],{"class":286}," -o",[197,1637,1638],{"class":286}," client\u002Ftypes.ts\n",[182,1640,1642],{"id":1641},"test-the-spec","Test the spec",[187,1644,1646],{"className":189,"code":1645,"language":191,"meta":192,"style":192},"func TestSpecCoversUsers(t *testing.T) {\n    app := buildApp()\n    spec := openapi.NewGenerator().GenerateFromApp(app)\n\n    item, ok := spec.Paths[\"\u002Fapi\u002Fv1\u002Fusers\u002F{id}\"]\n    if !ok {\n        t.Fatal(\"missing path\")\n    }\n    if item.Get == nil {\n        t.Fatal(\"missing GET operation\")\n    }\n    if len(item.Get.Parameters) == 0 {\n        t.Fatal(\"expected the id path parameter\")\n    }\n}\n",[194,1647,1648,1674,1684,1706,1710,1743,1756,1777,1782,1802,1821,1825,1857,1876,1880],{"__ignoreMap":192},[197,1649,1650,1652,1655,1657,1660,1662,1665,1667,1670,1672],{"class":199,"line":200},[197,1651,1492],{"class":207},[197,1653,1654],{"class":235}," TestSpecCoversUsers",[197,1656,239],{"class":207},[197,1658,1659],{"class":1321},"t",[197,1661,1337],{"class":207},[197,1663,1664],{"class":211},"testing",[197,1666,232],{"class":207},[197,1668,1669],{"class":211},"T",[197,1671,1347],{"class":207},[197,1673,585],{"class":207},[197,1675,1676,1678,1680,1682],{"class":199,"line":218},[197,1677,1505],{"class":228},[197,1679,956],{"class":207},[197,1681,1510],{"class":235},[197,1683,967],{"class":207},[197,1685,1686,1688,1690,1692,1694,1696,1698,1700,1702,1704],{"class":199,"line":225},[197,1687,1520],{"class":228},[197,1689,956],{"class":207},[197,1691,959],{"class":228},[197,1693,232],{"class":207},[197,1695,964],{"class":235},[197,1697,890],{"class":207},[197,1699,1430],{"class":235},[197,1701,239],{"class":207},[197,1703,242],{"class":228},[197,1705,245],{"class":207},[197,1707,1708],{"class":199,"line":620},[197,1709,222],{"emptyLinePlaceholder":221},[197,1711,1712,1715,1717,1720,1722,1725,1727,1730,1733,1735,1738,1740],{"class":199,"line":635},[197,1713,1714],{"class":228},"    item",[197,1716,281],{"class":207},[197,1718,1719],{"class":228}," ok ",[197,1721,956],{"class":207},[197,1723,1724],{"class":228}," spec",[197,1726,232],{"class":207},[197,1728,1729],{"class":228},"Paths",[197,1731,1732],{"class":207},"[",[197,1734,290],{"class":207},[197,1736,1737],{"class":286},"\u002Fapi\u002Fv1\u002Fusers\u002F{id}",[197,1739,290],{"class":207},[197,1741,1742],{"class":207},"]\n",[197,1744,1745,1748,1751,1754],{"class":199,"line":652},[197,1746,1747],{"class":203},"    if",[197,1749,1750],{"class":207}," !",[197,1752,1753],{"class":228},"ok ",[197,1755,990],{"class":207},[197,1757,1758,1761,1763,1766,1768,1770,1773,1775],{"class":199,"line":667},[197,1759,1760],{"class":228},"        t",[197,1762,232],{"class":207},[197,1764,1765],{"class":235},"Fatal",[197,1767,239],{"class":207},[197,1769,290],{"class":207},[197,1771,1772],{"class":286},"missing path",[197,1774,290],{"class":207},[197,1776,245],{"class":207},[197,1778,1779],{"class":199,"line":682},[197,1780,1781],{"class":207},"    }\n",[197,1783,1784,1786,1789,1791,1794,1797,1800],{"class":199,"line":1121},[197,1785,1747],{"class":203},[197,1787,1788],{"class":228}," item",[197,1790,232],{"class":207},[197,1792,1793],{"class":228},"Get ",[197,1795,1796],{"class":207},"==",[197,1798,1799],{"class":207}," nil",[197,1801,585],{"class":207},[197,1803,1804,1806,1808,1810,1812,1814,1817,1819],{"class":199,"line":1155},[197,1805,1760],{"class":228},[197,1807,232],{"class":207},[197,1809,1765],{"class":235},[197,1811,239],{"class":207},[197,1813,290],{"class":207},[197,1815,1816],{"class":286},"missing GET operation",[197,1818,290],{"class":207},[197,1820,245],{"class":207},[197,1822,1823],{"class":199,"line":1186},[197,1824,1781],{"class":207},[197,1826,1827,1829,1832,1834,1837,1839,1842,1844,1847,1849,1852,1855],{"class":199,"line":1191},[197,1828,1747],{"class":203},[197,1830,1831],{"class":235}," len",[197,1833,239],{"class":207},[197,1835,1836],{"class":228},"item",[197,1838,232],{"class":207},[197,1840,1841],{"class":228},"Get",[197,1843,232],{"class":207},[197,1845,1846],{"class":228},"Parameters",[197,1848,1347],{"class":207},[197,1850,1851],{"class":207}," ==",[197,1853,1854],{"class":1582}," 0",[197,1856,585],{"class":207},[197,1858,1859,1861,1863,1865,1867,1869,1872,1874],{"class":199,"line":1196},[197,1860,1760],{"class":228},[197,1862,232],{"class":207},[197,1864,1765],{"class":235},[197,1866,239],{"class":207},[197,1868,290],{"class":207},[197,1870,1871],{"class":286},"expected the id path parameter",[197,1873,290],{"class":207},[197,1875,245],{"class":207},[197,1877,1878],{"class":199,"line":1230},[197,1879,1781],{"class":207},[197,1881,1882],{"class":199,"line":1246},[197,1883,685],{"class":207},[182,1885,1887],{"id":1886},"next-steps","Next steps",[789,1889,1890,1897],{},[792,1891,1892,1894,1895,232],{},[258,1893,136],{"href":137}," for the reference page served at ",[194,1896,255],{},[792,1898,1899,1902],{},[258,1900,1901],{"href":44},"Request binding"," for the tags the generator reads.",[1904,1905,1906],"style",{},"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 .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .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 pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":192,"searchDepth":218,"depth":218,"links":1908},[1909,1910,1911,1912,1913,1914,1915,1916,1917],{"id":184,"depth":218,"text":185},{"id":307,"depth":218,"text":308},{"id":565,"depth":218,"text":566},{"id":773,"depth":218,"text":774},{"id":915,"depth":218,"text":916},{"id":937,"depth":218,"text":938},{"id":1456,"depth":218,"text":1457},{"id":1641,"depth":218,"text":1642},{"id":1886,"depth":218,"text":1887},"Generate an OpenAPI 3 document from your handler types and struct tags.","md",null,{},{"icon":134},{"title":131,"description":1918},"LCpGITWG0oCcN-suF0ehm-MyIITs1l_-rTjoB1vaJxU",[1926,1928],{"title":120,"path":121,"stem":122,"description":1927,"icon":123,"children":-1},"Configure GoTrue to sit behind ezz, run it locally with Docker, and refresh the golden fixtures.",{"title":136,"path":137,"stem":138,"description":1929,"icon":139,"children":-1},"Serve an interactive API reference next to your spec, and style it.",1784970045269]