{"id":6095,"date":"2025-09-29T10:30:35","date_gmt":"2025-09-29T17:30:35","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=6095"},"modified":"2026-02-23T11:32:26","modified_gmt":"2026-02-23T19:32:26","slug":"data-api-builder-16-http-headers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/data-api-builder-16-http-headers\/","title":{"rendered":"Data API builder\u00a01.6: Advanced Behaviors with Special HTTP Headers"},"content":{"rendered":"<p data-start=\"0\" data-end=\"300\">\n  Data API builder (DAB) provides REST and GraphQL endpoints over SQL Server, Azure Cosmos DB, PostgreSQL, MySQL, and SQL Data Warehouse. REST endpoints support several HTTP headers that let you control how requests behave. These headers give you precision over updates, caching, and discovering new resources.\n<\/p>\n<h2 data-start=\"302\" data-end=\"311\">\n  If-Match\n<\/h2>\n<p data-start=\"313\" data-end=\"600\">\n  By default, DAB treats <code data-start=\"335\" data-end=\"338\">PUT<\/code> and <code data-start=\"343\" data-end=\"348\">PATCH<\/code> as upserts: update if the row exists, insert if not. Sometimes you need stricter semantics. <code data-start=\"473\" data-end=\"482\">If-Match<\/code> provides update-only behavior.\n<\/p>\n<p data-start=\"602\" data-end=\"690\">\n  <code data-start=\"602\" data-end=\"611\">If-Match<\/code> in DAB only supports <code data-start=\"646\" data-end=\"649\">*<\/code>. Any other value is rejected.\n<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" data-start=\"692\" data-end=\"970\">\n<thead data-start=\"692\" data-end=\"755\">\n<tr data-start=\"692\" data-end=\"755\">\n<th data-start=\"692\" data-end=\"710\" data-col-size=\"sm\">\n            Header value\n          <\/th>\n<th data-start=\"710\" data-end=\"755\" data-col-size=\"md\">\n            Behavior\n          <\/th>\n<\/tr>\n<\/thead>\n<tbody data-start=\"757\" data-end=\"970\">\n<tr data-start=\"757\" data-end=\"820\">\n<td data-start=\"757\" data-end=\"772\" data-col-size=\"sm\">\n            <code data-start=\"759\" data-end=\"770\">If-Match: *<\/code>\n          <\/td>\n<td data-start=\"772\" data-end=\"820\" data-col-size=\"md\">\n            Update only if the row exists; otherwise <code data-start=\"795\" data-end=\"810\">404 Not Found<\/code>.\n          <\/td>\n<\/tr>\n<tr data-start=\"822\" data-end=\"880\">\n<td data-start=\"822\" data-end=\"835\" data-col-size=\"sm\">\n            Absent\n          <\/td>\n<td data-start=\"835\" data-end=\"880\" data-col-size=\"md\">\n            Default upsert (insert if missing, update if found).\n          <\/td>\n<\/tr>\n<tr data-start=\"882\" data-end=\"970\">\n<td data-start=\"882\" data-end=\"901\" data-col-size=\"sm\">\n            Anything else\n          <\/td>\n<td data-start=\"901\" data-end=\"970\" data-col-size=\"md\">\n            Rejected with <code data-start=\"918\" data-end=\"935\">400 Bad Request<\/code>.\n          <\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<\/div>\n<p data-start=\"972\" data-end=\"1050\">\n  Example request that only updates if the row exists:\n<\/p>\n<div class=\"contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary\">\n<div class=\"sticky top-9\">\n<div class=\"absolute end-0 bottom-0 flex h-9 items-center pe-2\">\n<div class=\"bg-token-bg-elevated-secondary text-token-text-secondary flex items-center gap-4 rounded-sm px-2 font-sans text-xs\">\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">PUT \/api\/Books\/id\/1\nIf-Match: *\nContent-Type: application\/json\n\n{\n  \"title\": \"The Return of the King\"\n}<\/code><\/pre>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/div>\n<p data-start=\"1052\" data-end=\"1200\">\n  If the record exists, you get <code data-start=\"1080\" data-end=\"1087\">200 OK<\/code>. If not, you get <code data-start=\"1105\" data-end=\"1120\">404 Not Found<\/code>. This applies to both <code data-start=\"1142\" data-end=\"1145\">PUT<\/code> and <code data-start=\"1150\" data-end=\"1155\">PATCH<\/code>. DAB does not support ETag comparisons or concurrency tokens.\n<\/p>\n<p style=\"padding-left: 40px;\" data-start=\"1052\" data-end=\"1200\">\n  Read the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/data-api-builder\/concept\/api\/http-if-match\">documentation on If-Match<\/a>.\n<\/p>\n<h2 data-start=\"1202\" data-end=\"1215\">\n  Cache-Control\n<\/h2>\n<p data-start=\"1217\" data-end=\"1400\">\n  DAB can cache query results in memory or in a distributed cache. The <code data-start=\"1254\" data-end=\"1267\">Cache-Control<\/code> request header lets you override cache behavior. This applies only to DAB\u2019s cache, not browsers or CDNs.\n<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" data-start=\"1402\" data-end=\"1700\">\n<thead data-start=\"1402\" data-end=\"1450\">\n<tr data-start=\"1402\" data-end=\"1450\">\n<th data-start=\"1402\" data-end=\"1420\" data-col-size=\"sm\">\n            Directive\n          <\/th>\n<th data-start=\"1420\" data-end=\"1450\" data-col-size=\"md\">\n            Behavior\n          <\/th>\n<\/tr>\n<\/thead>\n<tbody data-start=\"1452\" data-end=\"1700\">\n<tr data-start=\"1452\" data-end=\"1520\">\n<td data-start=\"1452\" data-end=\"1475\" data-col-size=\"sm\">\n            <code data-start=\"1454\" data-end=\"1474\">no-cache<\/code>\n          <\/td>\n<td data-start=\"1475\" data-end=\"1520\" data-col-size=\"md\">\n            Always query DB and refresh the cache.\n          <\/td>\n<\/tr>\n<tr data-start=\"1522\" data-end=\"1580\">\n<td data-start=\"1522\" data-end=\"1546\" data-col-size=\"sm\">\n            <code data-start=\"1524\" data-end=\"1545\">no-store<\/code>\n          <\/td>\n<td data-start=\"1546\" data-end=\"1580\" data-col-size=\"md\">\n            Return cache if present; otherwise query DB but don\u2019t store.\n          <\/td>\n<\/tr>\n<tr data-start=\"1582\" data-end=\"1660\">\n<td data-start=\"1582\" data-end=\"1615\" data-col-size=\"sm\">\n            <code data-start=\"1584\" data-end=\"1614\">only-if-cached<\/code>\n          <\/td>\n<td data-start=\"1615\" data-end=\"1660\" data-col-size=\"md\">\n            Return cached result only, else <code data-start=\"1640\" data-end=\"1658\">504 Gateway Timeout<\/code>.\n          <\/td>\n<\/tr>\n<tr data-start=\"1662\" data-end=\"1700\">\n<td data-start=\"1662\" data-end=\"1680\" data-col-size=\"sm\">\n            Absent\n          <\/td>\n<td data-start=\"1680\" data-end=\"1700\" data-col-size=\"md\">\n            Default: return cache if present, else query and cache.\n          <\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> Request example using <\/p>\n<p>    <code data-start=\"2075\" data-end=\"2082\">no-cache<\/code>. <\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">GET \/api\/Books\nCache-Control: no-cache\nAccept: application\/json<\/code><\/pre>\n<\/p><\/div>\n<\/div>\n<p style=\"padding-left: 40px;\" data-start=\"1702\" data-end=\"1712\">\n  Read the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/data-api-builder\/concept\/cache\/http-headers\">documentation on Cache headers<\/a>.\n<\/p>\n<h2 data-start=\"1702\" data-end=\"1712\">\n  Location\n<\/h2>\n<p data-start=\"1714\" data-end=\"1850\">\n  When you create a resource with <code data-start=\"1738\" data-end=\"1742\">POST<\/code>, DAB includes a <code data-start=\"1765\" data-end=\"1773\">Location<\/code> header showing the path of the new record. For <code data-start=\"1810\" data-end=\"1813\">PUT<\/code> or <code data-start=\"1818\" data-end=\"1823\">PATCH<\/code> that insert rows, it may be omitted.\n<\/p>\n<ul data-start=\"1852\" data-end=\"2000\">\n<li data-start=\"1852\" data-end=\"1900\">\n    <code data-start=\"1854\" data-end=\"1858\">POST<\/code> inserts: <code data-start=\"1872\" data-end=\"1884\">201 Created<\/code> with <code data-start=\"1890\" data-end=\"1899\">Location<\/code>.\n  <\/li>\n<li data-start=\"1901\" data-end=\"1950\">\n    <code data-start=\"1903\" data-end=\"1906\">PUT<\/code>\/<code data-start=\"1910\" data-end=\"1915\">PATCH<\/code> updates: <code data-start=\"1930\" data-end=\"1940\">200 OK<\/code>, no <code data-start=\"1947\" data-end=\"1956\">Location<\/code>.\n  <\/li>\n<li data-start=\"1951\" data-end=\"2000\">\n    <code data-start=\"1953\" data-end=\"1956\">PUT<\/code>\/<code data-start=\"1960\" data-end=\"1965\">PATCH<\/code> inserts: <code data-start=\"1979\" data-end=\"1990\">201 Created<\/code>, <code data-start=\"1995\" data-end=\"2004\">Location<\/code> may be omitted.\n  <\/li>\n<\/ul>\n<p data-start=\"2002\" data-end=\"2120\">\n  After creating a book with <code data-start=\"2034\" data-end=\"2038\">POST<\/code>, you will see <code data-start=\"2065\" data-end=\"2073\">Location<\/code>: <code data-start=\"2075\" data-end=\"2082\">id\/123<\/code>. Clients can then immediately fetch <code data-start=\"2105\" data-end=\"2119\">\/api\/Books\/id\/123<\/code>.\n<\/p>\n<p data-start=\"2002\" data-end=\"2120\">\n  Example POST response:\n<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">HTTP\/1.1 201 Created\nLocation: id\/123\nContent-Type: application\/json\n\n{\n  \"id\": 123,\n  \"title\": \"New Book\"\n}<\/code><\/pre>\n<p style=\"padding-left: 40px;\" data-start=\"2122\" data-end=\"2135\">\n  Read the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/data-api-builder\/concept\/api\/http-location\">documentation on Location<\/a>.\n<\/p>\n<h2 data-start=\"2122\" data-end=\"2135\">\n  Summary\n<\/h2>\n<p data-start=\"2137\" data-end=\"2250\">\n  Use <code data-start=\"2141\" data-end=\"2149\">If-Match<\/code> for strict updates, <code data-start=\"2182\" data-end=\"2195\">Cache-Control<\/code> to tune caching, and <code data-start=\"2228\" data-end=\"2236\">Location<\/code> to discover new resources. Together, these headers make your APIs predictable and reliable.\n<\/p>\n<p data-start=\"2137\" data-end=\"2250\">\n  <div  class=\"d-flex justify-content-left\"><a class=\"cta_button_link btn-primary mb-24\" href=\"https:\/\/aka.ms\/dab\/docs\" target=\"_blank\">Get Started with Data API builder<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Data API builder (DAB) provides REST and GraphQL endpoints over SQL Server, Azure Cosmos DB, PostgreSQL, MySQL, and SQL Data Warehouse. REST endpoints support several HTTP headers that let you control how requests behave. These headers give you precision over updates, caching, and discovering new resources. If-Match By default, DAB treats PUT and PATCH as [&hellip;]<\/p>\n","protected":false},"author":96788,"featured_media":6610,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,597],"tags":[560,521],"class_list":["post-6095","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sql","category-data-api-builder-2","tag-data-api-builder","tag-http"],"acf":[],"blog_post_summary":"<p>Data API builder (DAB) provides REST and GraphQL endpoints over SQL Server, Azure Cosmos DB, PostgreSQL, MySQL, and SQL Data Warehouse. REST endpoints support several HTTP headers that let you control how requests behave. These headers give you precision over updates, caching, and discovering new resources. If-Match By default, DAB treats PUT and PATCH as [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/6095","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/96788"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=6095"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/6095\/revisions"}],"predecessor-version":[{"id":6611,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/6095\/revisions\/6611"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/6610"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=6095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=6095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=6095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}