[{"data":1,"prerenderedAt":560},["ShallowReactive",2],{"docs:\u002Fdocs":3,"i-lucide:moon":551,"i-lucide:github":556,"i-lucide:menu":558},{"id":4,"title":5,"body":6,"description":544,"extension":545,"meta":546,"navigation":112,"path":547,"seo":548,"stem":549,"__hash__":550},"docs\u002Fdocs\u002Findex.md","Introduction",{"type":7,"value":8,"toc":539},"minimark",[9,13,63,68,71,324,327,457,464,468,477,487,491,519,535],[10,11,12],"p",{},"Nuxt Endpoints lets you describe an HTTP endpoint once, next to its handler, with the schema library you already use — Zod, Valibot, or Effect Schema. Everything else is derived from that single definition:",[14,15,16,40,53],"ul",{},[17,18,19,23,24,28,29,28,32,35,36,39],"li",{},[20,21,22],"strong",{},"Runtime validation"," — ",[25,26,27],"code",{},"params",", ",[25,30,31],{},"query",[25,33,34],{},"headers",", and ",[25,37,38],{},"body"," are validated before your handler runs. Handler code sees parsed schema output, so coercion and transforms are already applied.",[17,41,42,23,45,48,49,52],{},[20,43,44],{},"A fully typed client",[25,46,47],{},"$endpoint"," and ",[25,50,51],{},"useEndpoint"," are generated from your routes. Request options, success bodies, and declared error responses are all inferred. No codegen step, no types to import.",[17,54,55,58,59,62],{},[20,56,57],{},"OpenAPI 3.1"," — a document generated from the same schemas, served at ",[25,60,61],{},"\u002F_endpoints\u002Fschema",". There is no separate spec to maintain, so it cannot go stale.",[64,65,67],"h2",{"id":66},"show-me","Show me",[10,69,70],{},"One route file declares the contract and the handler:",[72,73,78],"pre",{"className":74,"code":75,"language":76,"meta":77,"style":77},"language-ts shiki shiki-themes github-light-default github-dark-default","\u002F\u002F server\u002Fapi\u002Fusers\u002F[id].get.ts\nimport { z } from 'zod'\n\nexport default defineEndpoint({\n  summary: 'Get a user',\n  params: z.object({ id: z.coerce.number() }),\n  responses: {\n    200: z.object({ id: z.number(), name: z.string() }),\n    404: z.object({ message: z.string() }),\n  },\n  handler: ({ params, respond }) => {\n    const user = findUser(params.id) \u002F\u002F params.id is a number — validated and coerced\n    if (!user) return respond(404, { message: 'Not found' })\n    return user\n  },\n})\n","ts","",[25,79,80,89,107,114,131,143,163,169,195,212,220,245,266,302,311,318],{"__ignoreMap":77},[81,82,85],"span",{"class":83,"line":84},"line",1,[81,86,88],{"class":87},"sA0OV","\u002F\u002F server\u002Fapi\u002Fusers\u002F[id].get.ts\n",[81,90,92,96,100,103],{"class":83,"line":91},2,[81,93,95],{"class":94},"swxxe","import",[81,97,99],{"class":98},"saQ_J"," { z } ",[81,101,102],{"class":94},"from",[81,104,106],{"class":105},"sZItA"," 'zod'\n",[81,108,110],{"class":83,"line":109},3,[81,111,113],{"emptyLinePlaceholder":112},true,"\n",[81,115,117,120,123,127],{"class":83,"line":116},4,[81,118,119],{"class":94},"export",[81,121,122],{"class":94}," default",[81,124,126],{"class":125},"s9HWX"," defineEndpoint",[81,128,130],{"class":129},"sVS1I","({\n",[81,132,134,137,140],{"class":83,"line":133},5,[81,135,136],{"class":98},"  summary: ",[81,138,139],{"class":105},"'Get a user'",[81,141,142],{"class":129},",\n",[81,144,146,149,152,155,158,161],{"class":83,"line":145},6,[81,147,148],{"class":98},"  params: z.",[81,150,151],{"class":125},"object",[81,153,154],{"class":98},"({ id: z.coerce.",[81,156,157],{"class":125},"number",[81,159,160],{"class":98},"() })",[81,162,142],{"class":129},[81,164,166],{"class":83,"line":165},7,[81,167,168],{"class":98},"  responses: {\n",[81,170,172,176,179,181,184,186,189,192],{"class":83,"line":171},8,[81,173,175],{"class":174},"sOOdx","    200",[81,177,178],{"class":98},": z.",[81,180,151],{"class":125},[81,182,183],{"class":98},"({ id: z.",[81,185,157],{"class":125},[81,187,188],{"class":98},"(), name: z.",[81,190,191],{"class":125},"string",[81,193,194],{"class":98},"() }),\n",[81,196,198,201,203,205,208,210],{"class":83,"line":197},9,[81,199,200],{"class":174},"    404",[81,202,178],{"class":98},[81,204,151],{"class":125},[81,206,207],{"class":98},"({ message: z.",[81,209,191],{"class":125},[81,211,194],{"class":98},[81,213,215,218],{"class":83,"line":214},10,[81,216,217],{"class":98},"  }",[81,219,142],{"class":129},[81,221,223,226,229,231,233,236,239,242],{"class":83,"line":222},11,[81,224,225],{"class":125},"  handler",[81,227,228],{"class":98},": ({ ",[81,230,27],{"class":129},[81,232,28],{"class":98},[81,234,235],{"class":129},"respond",[81,237,238],{"class":98}," }) ",[81,240,241],{"class":94},"=>",[81,243,244],{"class":98}," {\n",[81,246,248,251,254,257,260,263],{"class":83,"line":247},12,[81,249,250],{"class":94},"    const",[81,252,253],{"class":174}," user",[81,255,256],{"class":94}," =",[81,258,259],{"class":125}," findUser",[81,261,262],{"class":98},"(params.id) ",[81,264,265],{"class":87},"\u002F\u002F params.id is a number — validated and coerced\n",[81,267,269,272,275,278,281,284,287,290,293,296,299],{"class":83,"line":268},13,[81,270,271],{"class":94},"    if",[81,273,274],{"class":98}," (",[81,276,277],{"class":94},"!",[81,279,280],{"class":98},"user) ",[81,282,283],{"class":94},"return",[81,285,286],{"class":125}," respond",[81,288,289],{"class":98},"(",[81,291,292],{"class":174},"404",[81,294,295],{"class":98},", { message: ",[81,297,298],{"class":105},"'Not found'",[81,300,301],{"class":98}," })\n",[81,303,305,308],{"class":83,"line":304},14,[81,306,307],{"class":94},"    return",[81,309,310],{"class":98}," user\n",[81,312,314,316],{"class":83,"line":313},15,[81,315,217],{"class":98},[81,317,142],{"class":129},[81,319,321],{"class":83,"line":320},16,[81,322,323],{"class":129},"})\n",[10,325,326],{},"Every component can now call it with full inference — including typed error branches:",[72,328,332],{"className":329,"code":330,"language":331,"meta":77,"style":77},"language-vue shiki shiki-themes github-light-default github-dark-default","\u003Cscript setup lang=\"ts\">\nconst result = await $endpoint('\u002Fapi\u002Fusers\u002F:id', {\n  method: 'get',\n  params: { id: '1' },\n}).result()\n\nif (result.status === 404) {\n  result.body.message \u002F\u002F typed as the 404 schema\n}\n\u003C\u002Fscript>\n","vue",[25,333,334,358,382,392,403,414,418,435,443,448],{"__ignoreMap":77},[81,335,336,339,343,346,349,352,355],{"class":83,"line":84},[81,337,338],{"class":98},"\u003C",[81,340,342],{"class":341},"snZHK","script",[81,344,345],{"class":174}," setup",[81,347,348],{"class":174}," lang",[81,350,351],{"class":98},"=",[81,353,354],{"class":105},"\"ts\"",[81,356,357],{"class":98},">\n",[81,359,360,363,366,368,371,374,376,379],{"class":83,"line":91},[81,361,362],{"class":94},"const",[81,364,365],{"class":174}," result",[81,367,256],{"class":94},[81,369,370],{"class":94}," await",[81,372,373],{"class":125}," $endpoint",[81,375,289],{"class":98},[81,377,378],{"class":105},"'\u002Fapi\u002Fusers\u002F:id'",[81,380,381],{"class":98},", {\n",[81,383,384,387,390],{"class":83,"line":109},[81,385,386],{"class":98},"  method: ",[81,388,389],{"class":105},"'get'",[81,391,142],{"class":98},[81,393,394,397,400],{"class":83,"line":116},[81,395,396],{"class":98},"  params: { id: ",[81,398,399],{"class":105},"'1'",[81,401,402],{"class":98}," },\n",[81,404,405,408,411],{"class":83,"line":133},[81,406,407],{"class":98},"}).",[81,409,410],{"class":125},"result",[81,412,413],{"class":98},"()\n",[81,415,416],{"class":83,"line":145},[81,417,113],{"emptyLinePlaceholder":112},[81,419,420,423,426,429,432],{"class":83,"line":165},[81,421,422],{"class":94},"if",[81,424,425],{"class":98}," (result.status ",[81,427,428],{"class":94},"===",[81,430,431],{"class":174}," 404",[81,433,434],{"class":98},") {\n",[81,436,437,440],{"class":83,"line":171},[81,438,439],{"class":98},"  result.body.message ",[81,441,442],{"class":87},"\u002F\u002F typed as the 404 schema\n",[81,444,445],{"class":83,"line":197},[81,446,447],{"class":98},"}\n",[81,449,450,453,455],{"class":83,"line":214},[81,451,452],{"class":98},"\u003C\u002F",[81,454,342],{"class":341},[81,456,357],{"class":98},[10,458,459,460,463],{},"Routes stay ordinary Nuxt server routes: plain HTTP, callable by mobile apps, other services, or ",[25,461,462],{},"curl",", and documented via the generated OpenAPI document.",[64,465,467],{"id":466},"adopt-at-your-own-pace","Adopt at your own pace",[10,469,470,471,476],{},"Adding the module changes nothing by itself. Only routes that export an endpoint definition are affected; every other route keeps working exactly as before. See ",[472,473,475],"a",{"href":474},"\u002Fdocs\u002Fincremental-adoption","Incremental Adoption",".",[478,479,480],"blockquote",{},[10,481,482,483,476],{},"Status: early alpha. The core endpoint flow is usable, but some OpenAPI and discovery details are intentionally still conservative. See ",[472,484,486],{"href":485},"\u002Fdocs\u002Flimits","Limits",[64,488,490],{"id":489},"next-steps","Next steps",[14,492,493,500,507],{},[17,494,495,499],{},[472,496,498],{"href":497},"\u002Fdocs\u002Fgetting-started","Getting Started"," — install the module and define your first endpoint.",[17,501,502,506],{},[472,503,505],{"href":504},"\u002Fdocs\u002Fendpoints","Define Endpoints"," — the full contract surface: request parts, multiple responses, validation options.",[17,508,509,513,514,48,516,518],{},[472,510,512],{"href":511},"\u002Fdocs\u002Fclient","Generated Client"," — everything ",[25,515,47],{},[25,517,51],{}," can do.",[10,520,521,522,48,526,530,531,476],{},"Curious how it works and why it is designed this way? Read the ",[472,523,525],{"href":524},"\u002Fdocs\u002Fmental-model","Mental Model",[472,527,529],{"href":528},"\u002Fdocs\u002Fwhy-nuxt-endpoints","Why Nuxt Endpoints?",", or see how it ",[472,532,534],{"href":533},"\u002Fdocs\u002Fcomparison","compares to alternatives",[536,537,538],"style",{},"html pre.shiki code .sA0OV, html code.shiki .sA0OV{--shiki-light:#6E7781;--shiki-dark:#8B949E}html pre.shiki code .swxxe, html code.shiki .swxxe{--shiki-light:#CF222E;--shiki-dark:#FF7B72}html pre.shiki code .saQ_J, html code.shiki .saQ_J{--shiki-light:#1F2328;--shiki-dark:#E6EDF3}html pre.shiki code .sZItA, html code.shiki .sZItA{--shiki-light:#0A3069;--shiki-dark:#A5D6FF}html pre.shiki code .s9HWX, html code.shiki .s9HWX{--shiki-light:#8250DF;--shiki-dark:#D2A8FF}html pre.shiki code .sVS1I, html code.shiki .sVS1I{--shiki-light:#953800;--shiki-dark:#FFA657}html pre.shiki code .sOOdx, html code.shiki .sOOdx{--shiki-light:#0550AE;--shiki-dark:#79C0FF}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 .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 .snZHK, html code.shiki .snZHK{--shiki-light:#116329;--shiki-dark:#7EE787}",{"title":77,"searchDepth":91,"depth":91,"links":540},[541,542,543],{"id":66,"depth":91,"text":67},{"id":466,"depth":91,"text":467},{"id":489,"depth":91,"text":490},"Typed APIs, generated clients, and OpenAPI for Nuxt server routes — from one endpoint definition.","md",{},"\u002Fdocs",{"title":5,"description":544},"docs\u002Findex","t6baQN8feZ9hPXtoJXqFRSLfI8wnQa6usILrIvH_7XU",{"left":552,"top":552,"width":553,"height":553,"rotate":552,"vFlip":554,"hFlip":554,"body":555},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":552,"top":552,"width":553,"height":553,"rotate":552,"vFlip":554,"hFlip":554,"body":557,"hidden":112},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5c.08-1.25-.27-2.48-1-3.5c.28-1.15.28-2.35 0-3.5c0 0-1 0-3 1.5c-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 4 9c0 3.5 3 5.5 6 5.5c-.39.49-.68 1.05-.85 1.65S8.93 17.38 9 18v4\"\u002F>\u003Cpath d=\"M9 18c-4.51 2-5-2-7-2\"\u002F>\u003C\u002Fg>",{"left":552,"top":552,"width":553,"height":553,"rotate":552,"vFlip":554,"hFlip":554,"body":559},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",1787723882160]