[{"data":1,"prerenderedAt":857},["ShallowReactive",2],{"navigation":3,"-examples-handle-query":193,"-examples-handle-query-surround":852},[4,91,138,170,177],{"title":5,"path":6,"stem":7,"children":8,"icon":90},"Guide","/guide","1.guide/0.index",[9,12,53,69],{"title":10,"path":6,"stem":7,"icon":11},"Getting Started","pixel:play",{"title":5,"icon":13,"path":14,"stem":15,"children":16,"page":52},"ph:book-open-duotone","/guide/basics","1.guide/1.basics",[17,22,27,32,37,42,47],{"title":18,"path":19,"stem":20,"icon":21},"Request Lifecycle","/guide/basics/lifecycle","1.guide/1.basics/1.lifecycle","icon-park-outline:handle-round",{"title":23,"path":24,"stem":25,"icon":26},"Routing","/guide/basics/routing","1.guide/1.basics/2.routing","solar:routing-bold",{"title":28,"path":29,"stem":30,"icon":31},"Middleware","/guide/basics/middleware","1.guide/1.basics/3.middleware","mdi:middleware-outline",{"title":33,"path":34,"stem":35,"icon":36},"Event Handlers","/guide/basics/handler","1.guide/1.basics/4.handler","mdi:function",{"title":38,"path":39,"stem":40,"icon":41},"Sending Response","/guide/basics/response","1.guide/1.basics/5.response","tabler:json",{"title":43,"path":44,"stem":45,"icon":46},"Error Handling","/guide/basics/error","1.guide/1.basics/6.error","tabler:error-404",{"title":48,"path":49,"stem":50,"icon":51},"Nested Apps","/guide/basics/nested-apps","1.guide/1.basics/7.nested-apps","material-symbols-light:layers-outline",false,{"title":54,"icon":55,"path":56,"stem":57,"children":58,"page":52},"API","material-symbols-light:api-rounded","/guide/api","1.guide/900.api",[59,64],{"title":60,"path":61,"stem":62,"icon":63},"H3","/guide/api/h3","1.guide/900.api/1.h3","material-symbols:bolt-rounded",{"title":65,"path":66,"stem":67,"icon":68},"H3Event","/guide/api/h3event","1.guide/900.api/2.h3event","material-symbols:data-object-rounded",{"title":70,"icon":71,"path":72,"stem":73,"children":74,"page":52},"Advanced","hugeicons:more-01","/guide/advanced","1.guide/901.advanced",[75,80,85],{"title":76,"path":77,"stem":78,"icon":79},"Plugins","/guide/advanced/plugins","1.guide/901.advanced/1.plugins","clarity:plugin-line",{"title":81,"path":82,"stem":83,"icon":84},"WebSockets","/guide/advanced/websocket","1.guide/901.advanced/2.websocket","hugeicons:live-streaming-02",{"title":86,"path":87,"stem":88,"icon":89},"Nightly Builds","/guide/advanced/nightly","1.guide/901.advanced/9.nightly","game-icons:barn-owl","i-ph:book-open-duotone",{"title":92,"path":93,"stem":94,"children":95,"icon":97},"Utils","/utils","2.utils/0.index",[96,98,103,108,113,118,123,128,133],{"title":92,"path":93,"stem":94,"icon":97},"ph:function-bold",{"title":99,"path":100,"stem":101,"icon":102},"Request","/utils/request","2.utils/1.request","material-symbols-light:input",{"title":104,"path":105,"stem":106,"icon":107},"Response","/utils/response","2.utils/2.response","material-symbols-light:output",{"title":109,"path":110,"stem":111,"icon":112},"Cookie","/utils/cookie","2.utils/3.cookie","material-symbols:cookie-outline",{"title":114,"path":115,"stem":116,"icon":117},"Security","/utils/security","2.utils/4.security","wpf:key-security",{"title":119,"path":120,"stem":121,"icon":122},"Proxy","/utils/proxy","2.utils/5.proxy","arcticons:super-proxy",{"title":124,"path":125,"stem":126,"icon":127},"MCP","/utils/mcp","2.utils/6.mcp","material-symbols:swap-calls",{"title":129,"path":130,"stem":131,"icon":132},"More utils","/utils/more","2.utils/9.more","mingcute:plus-line",{"title":134,"path":135,"stem":136,"icon":137},"Community","/utils/community","2.utils/99.community","lets-icons:external",{"title":139,"path":140,"stem":141,"children":142,"icon":144},"Examples","/examples","4.examples/0.index",[143,145,150,154,158,162,166],{"title":139,"path":140,"stem":141,"icon":144},"ph:code",{"title":146,"path":147,"stem":148,"icon":149},"Cookies","/examples/handle-cookie","4.examples/handle-cookie","ph:arrow-right",{"title":151,"path":152,"stem":153,"icon":149},"HTTP QUERY Method","/examples/handle-query","4.examples/handle-query",{"title":155,"path":156,"stem":157,"icon":149},"Sessions","/examples/handle-session","4.examples/handle-session",{"title":159,"path":160,"stem":161,"icon":149},"Static Assets","/examples/serve-static-assets","4.examples/serve-static-assets",{"title":163,"path":164,"stem":165,"icon":149},"Stream Response","/examples/stream-response","4.examples/stream-response",{"title":167,"path":168,"stem":169,"icon":149},"Validate Data","/examples/validate-data","4.examples/validate-data",{"title":171,"path":172,"stem":173,"children":174,"icon":176},"Migration","/migration","5.migration/0.index",[175],{"title":171,"path":172,"stem":173,"icon":176},"icons8:up-round",{"title":178,"path":179,"stem":180,"children":181},"Blog","/blog","99.blog",[182,185,189],{"title":178,"path":179,"stem":183,"icon":184},"99.blog/index","i-lucide-file-text",{"title":186,"path":187,"stem":188,"icon":184},"H3 1.8 - Towards the Edge of the Web","/blog/v1.8","99.blog/1.v1.8",{"title":190,"path":191,"stem":192,"icon":184},"H3 v2 beta","/blog/v2-beta","99.blog/2.v2-beta",{"id":194,"title":151,"body":195,"description":846,"extension":847,"meta":848,"navigation":849,"path":152,"seo":850,"stem":153,"__hash__":851},"content/4.examples/handle-query.md",{"type":196,"value":197,"toc":836,"icon":149},"minimark",[198,232,245,253,260,383,397,401,426,509,515,536,636,643,658,766,770,786,803,832],[199,200,201,202,214,215,218,219,223,224,227,228,231],"p",{},"The ",[203,204,208,209,213],"a",{"href":205,"rel":206},"https://www.rfc-editor.org/rfc/rfc10008",[207],"nofollow","HTTP ",[210,211,212],"code",{},"QUERY"," method (RFC 10008)"," is like ",[210,216,217],{},"GET"," — ",[220,221,222],"strong",{},"safe, idempotent, and cacheable"," — but carries a query in the request ",[220,225,226],{},"body"," with a ",[210,229,230],{},"Content-Type",". It's the standard answer to \"I need a GET, but my query is too large or too structured for the URL\".",[199,233,234,235,237,238,244],{},"H3 supports ",[210,236,212],{}," as a first-class method via ",[203,239,241],{"href":240},"/guide/basics/routing#http-query-method",[210,242,243],{},"app.query()",", plus two helper utilities.",[246,247,249,250,252],"h2",{"id":248},"register-a-query-handler","Register a ",[210,251,212],{}," Handler",[199,254,255,256,259],{},"Read the request body just like you would for a ",[210,257,258],{},"POST",":",[261,262,267],"pre",{"className":263,"code":264,"language":265,"meta":266,"style":266},"language-ts shiki shiki-themes github-light github-dark github-dark","import { readBody } from \"h3\";\n\napp.query(\"/books\", async (event) => {\n  const query = await readBody(event, { type: \"text\" });\n  return runSearch(query);\n});\n","ts","",[210,268,269,292,299,337,365,377],{"__ignoreMap":266},[270,271,274,278,282,285,289],"span",{"class":272,"line":273},"line",1,[270,275,277],{"class":276},"so5gQ","import",[270,279,281],{"class":280},"slsVL"," { readBody } ",[270,283,284],{"class":276},"from",[270,286,288],{"class":287},"sfrk1"," \"h3\"",[270,290,291],{"class":280},";\n",[270,293,295],{"class":272,"line":294},2,[270,296,298],{"emptyLinePlaceholder":297},true,"\n",[270,300,302,305,309,312,315,318,321,324,328,331,334],{"class":272,"line":301},3,[270,303,304],{"class":280},"app.",[270,306,308],{"class":307},"shcOC","query",[270,310,311],{"class":280},"(",[270,313,314],{"class":287},"\"/books\"",[270,316,317],{"class":280},", ",[270,319,320],{"class":276},"async",[270,322,323],{"class":280}," (",[270,325,327],{"class":326},"sQHwn","event",[270,329,330],{"class":280},") ",[270,332,333],{"class":276},"=>",[270,335,336],{"class":280}," {\n",[270,338,340,343,347,350,353,356,359,362],{"class":272,"line":339},4,[270,341,342],{"class":276},"  const",[270,344,346],{"class":345},"suiK_"," query",[270,348,349],{"class":276}," =",[270,351,352],{"class":276}," await",[270,354,355],{"class":307}," readBody",[270,357,358],{"class":280},"(event, { type: ",[270,360,361],{"class":287},"\"text\"",[270,363,364],{"class":280}," });\n",[270,366,368,371,374],{"class":272,"line":367},5,[270,369,370],{"class":276},"  return",[270,372,373],{"class":307}," runSearch",[270,375,376],{"class":280},"(query);\n",[270,378,380],{"class":272,"line":379},6,[270,381,382],{"class":280},"});\n",[199,384,385,386,388,389,393,394,396],{},"Because ",[210,387,212],{}," carries an attacker-controllable body, ",[203,390,392],{"href":391},"/utils/request#assertbodysizeevent-limit","body-size limits"," apply just like ",[210,395,258],{},".",[246,398,400],{"id":399},"advertise-accepted-formats","Advertise Accepted Formats",[199,402,403,404,410,411,414,415,420,421,423,424,259],{},"Use ",[203,405,407],{"href":406},"/utils/request#appendacceptqueryevent-mediatypes",[210,408,409],{},"appendAcceptQuery"," to tell clients which query formats a resource understands. It sets the ",[210,412,413],{},"Accept-Query"," response header (a ",[203,416,419],{"href":417,"rel":418},"https://www.rfc-editor.org/rfc/rfc8941",[207],"Structured Fields"," List), and can be set on a plain ",[210,422,217],{}," too so clients can discover formats before sending a ",[210,425,212],{},[261,427,429],{"className":263,"code":428,"language":265,"meta":266,"style":266},"import { appendAcceptQuery } from \"h3\";\n\napp.get(\"/books\", (event) => {\n  appendAcceptQuery(event, [\"application/sql\", \"application/jsonpath\"]);\n  // Accept-Query: application/sql, application/jsonpath\n  return \"Send a QUERY request with a SQL or JSONPath body.\";\n});\n",[210,430,431,444,448,470,489,495,504],{"__ignoreMap":266},[270,432,433,435,438,440,442],{"class":272,"line":273},[270,434,277],{"class":276},[270,436,437],{"class":280}," { appendAcceptQuery } ",[270,439,284],{"class":276},[270,441,288],{"class":287},[270,443,291],{"class":280},[270,445,446],{"class":272,"line":294},[270,447,298],{"emptyLinePlaceholder":297},[270,449,450,452,455,457,459,462,464,466,468],{"class":272,"line":301},[270,451,304],{"class":280},[270,453,454],{"class":307},"get",[270,456,311],{"class":280},[270,458,314],{"class":287},[270,460,461],{"class":280},", (",[270,463,327],{"class":326},[270,465,330],{"class":280},[270,467,333],{"class":276},[270,469,336],{"class":280},[270,471,472,475,478,481,483,486],{"class":272,"line":339},[270,473,474],{"class":307},"  appendAcceptQuery",[270,476,477],{"class":280},"(event, [",[270,479,480],{"class":287},"\"application/sql\"",[270,482,317],{"class":280},[270,484,485],{"class":287},"\"application/jsonpath\"",[270,487,488],{"class":280},"]);\n",[270,490,491],{"class":272,"line":367},[270,492,494],{"class":493},"sCsY4","  // Accept-Query: application/sql, application/jsonpath\n",[270,496,497,499,502],{"class":272,"line":379},[270,498,370],{"class":276},[270,500,501],{"class":287}," \"Send a QUERY request with a SQL or JSONPath body.\"",[270,503,291],{"class":280},[270,505,507],{"class":272,"line":506},7,[270,508,382],{"class":280},[246,510,512,513],{"id":511},"validate-the-content-type","Validate the ",[210,514,230],{},[199,516,403,517,523,524,527,528,531,532,535],{},[203,518,520],{"href":519},"/utils/request#requirecontenttypeevent-acceptedtypes",[210,521,522],{},"requireContentType"," to enforce the RFC's error semantics. It returns the matched media type, or throws ",[210,525,526],{},"400"," (missing), ",[210,529,530],{},"415"," (unsupported), or ",[210,533,534],{},"422"," (malformed):",[261,537,539],{"className":263,"code":538,"language":265,"meta":266,"style":266},"import { requireContentType, readBody } from \"h3\";\n\napp.query(\"/books\", async (event) => {\n  const type = requireContentType(event, [\"application/sql\", \"application/jsonpath\"]);\n  const query = await readBody(event, { type: \"text\" });\n  return runQuery(type, query);\n});\n",[210,540,541,554,558,582,604,622,632],{"__ignoreMap":266},[270,542,543,545,548,550,552],{"class":272,"line":273},[270,544,277],{"class":276},[270,546,547],{"class":280}," { requireContentType, readBody } ",[270,549,284],{"class":276},[270,551,288],{"class":287},[270,553,291],{"class":280},[270,555,556],{"class":272,"line":294},[270,557,298],{"emptyLinePlaceholder":297},[270,559,560,562,564,566,568,570,572,574,576,578,580],{"class":272,"line":301},[270,561,304],{"class":280},[270,563,308],{"class":307},[270,565,311],{"class":280},[270,567,314],{"class":287},[270,569,317],{"class":280},[270,571,320],{"class":276},[270,573,323],{"class":280},[270,575,327],{"class":326},[270,577,330],{"class":280},[270,579,333],{"class":276},[270,581,336],{"class":280},[270,583,584,586,589,591,594,596,598,600,602],{"class":272,"line":339},[270,585,342],{"class":276},[270,587,588],{"class":345}," type",[270,590,349],{"class":276},[270,592,593],{"class":307}," requireContentType",[270,595,477],{"class":280},[270,597,480],{"class":287},[270,599,317],{"class":280},[270,601,485],{"class":287},[270,603,488],{"class":280},[270,605,606,608,610,612,614,616,618,620],{"class":272,"line":367},[270,607,342],{"class":276},[270,609,346],{"class":345},[270,611,349],{"class":276},[270,613,352],{"class":276},[270,615,355],{"class":307},[270,617,358],{"class":280},[270,619,361],{"class":287},[270,621,364],{"class":280},[270,623,624,626,629],{"class":272,"line":379},[270,625,370],{"class":276},[270,627,628],{"class":307}," runQuery",[270,630,631],{"class":280},"(type, query);\n",[270,633,634],{"class":272,"line":506},[270,635,382],{"class":280},[246,637,639,640,642],{"id":638},"offer-a-cacheable-get-alternative","Offer a Cacheable ",[210,641,217],{}," Alternative",[199,644,645,646,648,649,651,652,655,656,259],{},"A ",[210,647,212],{}," response is not addressable by URL, so browsers and CDNs can't cache it. RFC 10008 suggests pointing clients at an equivalent, cacheable ",[210,650,217],{}," via the ",[210,653,654],{},"Content-Location"," header. Stash the result under a stable id and let a client repeat the query with an ordinary, HTTP-cacheable ",[210,657,217],{},[261,659,661],{"className":263,"code":660,"language":265,"meta":266,"style":266},"app.query(\"/books\", async (event) => {\n  const result = runQuery(type, query);\n  const id = queryId(type, query); // stable hash of the query\n  cache.set(id, result);\n  event.res.headers.set(\"content-location\", `/books/${id}`);\n  return result;\n});\n",[210,662,663,687,700,718,729,755,762],{"__ignoreMap":266},[270,664,665,667,669,671,673,675,677,679,681,683,685],{"class":272,"line":273},[270,666,304],{"class":280},[270,668,308],{"class":307},[270,670,311],{"class":280},[270,672,314],{"class":287},[270,674,317],{"class":280},[270,676,320],{"class":276},[270,678,323],{"class":280},[270,680,327],{"class":326},[270,682,330],{"class":280},[270,684,333],{"class":276},[270,686,336],{"class":280},[270,688,689,691,694,696,698],{"class":272,"line":294},[270,690,342],{"class":276},[270,692,693],{"class":345}," result",[270,695,349],{"class":276},[270,697,628],{"class":307},[270,699,631],{"class":280},[270,701,702,704,707,709,712,715],{"class":272,"line":301},[270,703,342],{"class":276},[270,705,706],{"class":345}," id",[270,708,349],{"class":276},[270,710,711],{"class":307}," queryId",[270,713,714],{"class":280},"(type, query); ",[270,716,717],{"class":493},"// stable hash of the query\n",[270,719,720,723,726],{"class":272,"line":339},[270,721,722],{"class":280},"  cache.",[270,724,725],{"class":307},"set",[270,727,728],{"class":280},"(id, result);\n",[270,730,731,734,736,738,741,743,746,749,752],{"class":272,"line":367},[270,732,733],{"class":280},"  event.res.headers.",[270,735,725],{"class":307},[270,737,311],{"class":280},[270,739,740],{"class":287},"\"content-location\"",[270,742,317],{"class":280},[270,744,745],{"class":287},"`/books/${",[270,747,748],{"class":280},"id",[270,750,751],{"class":287},"}`",[270,753,754],{"class":280},");\n",[270,756,757,759],{"class":272,"line":379},[270,758,370],{"class":276},[270,760,761],{"class":280}," result;\n",[270,763,764],{"class":272,"line":506},[270,765,382],{"class":280},[246,767,769],{"id":768},"full-example","Full Example",[199,771,772,773,776,777,779,780,782,783,396],{},"A self-contained, runnable demo — a ",[210,774,775],{},"/books"," resource that accepts SQL-ish and JSONPath queries, validates the ",[210,778,230],{},", and advertises a cacheable ",[210,781,217],{}," alternative. It also serves a small interactive page at ",[210,784,785],{},"/",[787,788,790],"read-more",{"to":789},"https://github.com/h3js/h3/tree/main/examples/query.mjs",[199,791,792,793,799,800,396],{},"See the full ",[203,794,796],{"href":789,"rel":795},[207],[210,797,798],{},"examples/query.mjs"," source, or run it locally with ",[210,801,802],{},"node examples/query.mjs",[804,805,806],"note",{},[199,807,808,809,317,811,813,814,817,818,821,822,828,829,396],{},"\nUnlike ",[210,810,217],{},[210,812,212],{}," is ",[220,815,816],{},"not"," CORS-safelisted, so browsers send a preflight. If you pass an explicit ",[210,819,820],{},"methods"," allowlist to ",[203,823,825],{"href":824},"/utils/security#handlecorsevent-options",[210,826,827],{},"handleCors",", include ",[210,830,831],{},"\"QUERY\"",[833,834,835],"style",{},"html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}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 .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":266,"searchDepth":294,"depth":294,"links":837},[838,840,841,843,845],{"id":248,"depth":294,"text":839},"Register a QUERY Handler",{"id":399,"depth":294,"text":400},{"id":511,"depth":294,"text":842},"Validate the Content-Type",{"id":638,"depth":294,"text":844},"Offer a Cacheable GET Alternative",{"id":768,"depth":294,"text":769},"Accept safe, cacheable requests that carry a query in the body.","md",{"icon":149},{"icon":149},{"title":151,"description":846},"RkCGul4gcCgAusgVTyYRSC8yZDDw95rPSv9g6YolUDk",[853,855],{"title":146,"path":147,"stem":148,"description":854,"icon":149,"children":-1},"Use cookies to store data on the client.",{"title":155,"path":156,"stem":157,"description":856,"icon":149,"children":-1},"Remember your users using a session.",1783698205464]