{"id":7183,"date":"2026-06-30T12:38:31","date_gmt":"2026-06-30T19:38:31","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=7183"},"modified":"2026-06-30T12:39:00","modified_gmt":"2026-06-30T19:39:00","slug":"data-api-builder-custom-rest-paths","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/data-api-builder-custom-rest-paths\/","title":{"rendered":"Compose your API surface with Data API builder custom paths"},"content":{"rendered":"<p>In May, Data API builder (DAB) 2.0 was released to preview, and in June it went generally available. With this new release, DAB introduced a new feature for REST endpoints: the ability to customize endpoints with compound paths. This feature allows developers to compose a sophisticated API surface dedicated to their business structure, not their database topology. Let&#8217;s take a look.<\/p>\n<h3>Generating REST endpoints<\/h3>\n<p>With Data API builder (DAB), developers can safely expose their production SQL database as a REST, GraphQL, and MCP endpoint. In this article, we focus on REST. These endpoints are dynamically generated by the DAB engine with rich capabilities like native pagination, filtering, projection, caching, and throttling. These are the same types of features you would add to your custom endpoints, but without the engineering cost or time.<\/p>\n<h3>Exposing REST endpoints<\/h3>\n<p>A REST endpoint path is constructed from three parts. The first is the host name where Data API builder is hosted. For example, this could be localhost in the inner developer loop or an Azure domain when hosted in Azure Container Apps. The second part is the global runtime setting <code>runtime.rest.path<\/code>, which defaults to <code>\/api<\/code>, a typical starting segment for most API endpoints.<\/p>\n<p>The third part of the REST path is our new feature, compound paths. It is individually configured for every entity. For example, if you have a <code>Customer<\/code> entity exposed, your default path might coalesce to <code>localhost\/api\/Customer<\/code>, which works great for many deployments and has worked great for years.<\/p>\n<p>However, entity path values like <code>\/external\/Customer<\/code> were not supported until release 2.0. With this new flexibility, different entities can be grouped by some business mnemonic to help clarify usage and enable better intuition around endpoint usage. Supporting as many subsegments as you need, Data API builder lets you compose your API surface in whatever direction best serves your business.<\/p>\n<h3>Entity configuration examples<\/h3>\n<p>Every entity provides its final REST endpoint path. This is the segment that now supports compound paths, letting you build out a tailored, intuitive API surface. In the examples below, we&#8217;ll show some scenarios with our example <code>Customer<\/code> entity.<\/p>\n<h4>Scenario 1: a simple endpoint<\/h4>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"runtime\": {\r\n    \"rest\": {\r\n      \"enabled\": true,\r\n      \"path\": \"\/api\"\r\n    }\r\n  },\r\n  \"entities\": {\r\n    \"Customer\": {\r\n      \"source\": {\r\n        \"object\": \"dbo.Customer\",\r\n        \"type\": \"table\"\r\n      },\r\n      \"rest\": {\r\n        \"enabled\": true,\r\n        \"path\": \"\/Customer\"\r\n      }\r\n    }\r\n  }\r\n}<\/code><\/pre>\n<p>The resulting REST path is <code>https:\/\/localhost\/api\/Customer<\/code>.<\/p>\n<h5>Or if you had several entities, you could see this:<\/h5>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">https:\/\/localhost\/api\/Customer\r\nhttps:\/\/localhost\/api\/Order\r\nhttps:\/\/localhost\/api\/Invoice\r\nhttps:\/\/localhost\/api\/CustomerAddress\r\nhttps:\/\/localhost\/api\/Payment<\/code><\/pre>\n<h4>Scenario 2: show the business in the path<\/h4>\n<p>You can use compound paths to organize endpoints by business area. This can make the API easier to understand, especially when many entities are exposed.<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"runtime\": {\r\n    \"rest\": {\r\n      \"enabled\": true,\r\n      \"path\": \"\/api\"\r\n    }\r\n  },\r\n  \"entities\": {\r\n    \"Customer\": {\r\n      \"source\": {\r\n        \"object\": \"dbo.Customer\",\r\n        \"type\": \"table\"\r\n      },\r\n      \"rest\": {\r\n        \"enabled\": true,\r\n        \"path\": \"\/sales\/Customer\"\r\n      }\r\n    }\r\n  }\r\n}<\/code><\/pre>\n<p>The resulting REST path is <code>https:\/\/localhost\/api\/sales\/Customer<\/code>.<\/p>\n<h5>Or if you had several entities, you could see this:<\/h5>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">https:\/\/localhost\/api\/sales\/Customer\r\nhttps:\/\/localhost\/api\/sales\/Order\r\nhttps:\/\/localhost\/api\/sales\/Invoice\r\nhttps:\/\/localhost\/api\/accounting\/Payment\r\nhttps:\/\/localhost\/api\/support\/CustomerCase<\/code><\/pre>\n<h4>Scenario 3: show the schema in the path<\/h4>\n<p>You can also use compound paths to reflect database schema or ownership. This can be useful when the API surface needs to preserve a familiar structure for developers.<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n  \"runtime\": {\r\n    \"rest\": {\r\n      \"enabled\": true,\r\n      \"path\": \"\/api\"\r\n    }\r\n  },\r\n  \"entities\": {\r\n    \"Customer\": {\r\n      \"source\": {\r\n        \"object\": \"sales.Customer\",\r\n        \"type\": \"table\"\r\n      },\r\n      \"rest\": {\r\n        \"enabled\": true,\r\n        \"path\": \"\/sales\/Customer\"\r\n      }\r\n    }\r\n  }\r\n}<\/code><\/pre>\n<p>The resulting REST path is <code>https:\/\/localhost\/api\/sales\/Customer<\/code>.<\/p>\n<h5>Or if you had several entities, you could see this:<\/h5>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">https:\/\/localhost\/api\/dbo\/Customer\r\nhttps:\/\/localhost\/api\/sales\/Order\r\nhttps:\/\/localhost\/api\/sales\/Invoice\r\nhttps:\/\/localhost\/api\/billing\/Payment\r\nhttps:\/\/localhost\/api\/support\/CustomerCase<\/code><\/pre>\n<h3>Conclusion<\/h3>\n<p>Compound REST paths make it easier to shape a Data API builder API around your application and business needs. You can keep simple paths when they are enough, or add structure when it helps developers understand and use the API. Data API builder still handles the endpoint generation, security, and query behavior for you.<\/p>\n<p>Best of luck!<\/p>\n<p><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 (DAB)<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Data API builder (DAB) 2.0 adds compound paths for REST endpoints, giving developers more control over how their API surface is organized. Instead of mirroring database topology, endpoints can now reflect simple names, business areas, or schema ownership.<\/p>\n","protected":false},"author":96788,"featured_media":7184,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[597,576],"tags":[560,410],"class_list":["post-7183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-api-builder-2","category-rest","tag-data-api-builder","tag-rest"],"acf":[],"blog_post_summary":"<p>Data API builder (DAB) 2.0 adds compound paths for REST endpoints, giving developers more control over how their API surface is organized. Instead of mirroring database topology, endpoints can now reflect simple names, business areas, or schema ownership.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7183","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=7183"}],"version-history":[{"count":1,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7183\/revisions"}],"predecessor-version":[{"id":7187,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/7183\/revisions\/7187"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/7184"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=7183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=7183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=7183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}