{"id":2751,"date":"2023-12-18T18:52:46","date_gmt":"2023-12-19T02:52:46","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=2751"},"modified":"2024-03-11T08:26:29","modified_gmt":"2024-03-11T15:26:29","slug":"data-api-builder-relationships","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/data-api-builder-relationships\/","title":{"rendered":"Relationship Advice from Data API builder"},"content":{"rendered":"<p><a href=\"https:\/\/aka.ms\/dab\">Data API builder<\/a> exposes REST endpoints for MySQL, PostgreSQL, Cosmos DB, SQL Server and Azure SQL. REST (Representational State Transfer) endpoints allow developers to easily query a single table, view or stored procedure. However, Data API builder also exposes GraphQL endpoints. Like REST, GraphQL returns data, but unlike REST, <strong>GraphQL can return data from multiple related tables in nested results<\/strong>. This includes one-to-many, many-to-many, and many-to-one relationships.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-overview.jpg\"><img decoding=\"async\" class=\"alignnone wp-image-2754 size-full\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-overview.jpg\" alt=\"Image dab overview\" width=\"743\" height=\"478\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-overview.jpg 743w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-overview-300x193.jpg 300w\" sizes=\"(max-width: 743px) 100vw, 743px\" \/><\/a><\/p>\n<p>This diagram illustrates a simple database that uses all three relationships. <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/data-api-builder\/relationships\">Data API builder supports each<\/a>, but to do so it is required that the configuration file describe bot the table and the relationship. Developers can edit the JSON fire directly or use the CLI to update the JSON programmatically. Let&#8217;s focus on the CLI approach as there&#8217;s <span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\">no question it is the easiest approach. Interacting JSON is simple but very prone to error. With the CLI, you don&#8217;t need to know the JSON schema. And with the CLI you don&#8217;t need to remember every command and closing brace.\u00a0<\/span><\/p>\n<h3>Adding tables<\/h3>\n<p>The CLI (dab) has an &#8220;add&#8221; command we use to add tables, views, or stored procedures to the configuration file. With it, we can configure the entity name, schema, and authentication. As of this article the supported flags and arguments are as follows:<\/p>\n<table style=\"width: 100%; height: 988px;\" width=\"100%\">\n<tbody>\n<tr style=\"height: 26px;\">\n<td style=\"height: 26px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>-s, &#8211;source<\/strong><\/span><\/td>\n<td style=\"height: 26px; width: 70.5%;\" width=\"58%\"><strong>Required<\/strong>. Name of the source database object.<\/td>\n<\/tr>\n<tr style=\"height: 70px;\">\n<td style=\"height: 70px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;permissions<\/strong><\/span><\/td>\n<td style=\"height: 70px; width: 70.5%;\" width=\"58%\"><strong>Required<\/strong>. Permissions required to access the source table or container.<\/td>\n<\/tr>\n<tr style=\"height: 70px;\">\n<td style=\"height: 70px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;source.type<\/strong><\/span><\/td>\n<td style=\"height: 70px; width: 70.5%;\" width=\"58%\">Type of the database object. Must be one of: [table, view, stored-procedure]<\/td>\n<\/tr>\n<tr style=\"height: 70px;\">\n<td style=\"height: 70px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;source.params<\/strong><\/span><\/td>\n<td style=\"height: 70px; width: 70.5%;\" width=\"58%\">Dictionary of parameters and their values for Source object. &#8220;param1:val1,param2:value2,..&#8221;<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;source.key-fields<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">The field(s) to be used as primary keys.<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;rest<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Route for rest API.<\/td>\n<\/tr>\n<tr style=\"height: 95px;\">\n<td style=\"height: 95px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;rest.methods<\/strong><\/span><\/td>\n<td style=\"height: 95px; width: 70.5%;\" width=\"58%\">HTTP actions to be supported for stored procedure. Specify the actions as a comma separated list. Valid HTTP actions are: [GET, POST, PUT, PATCH, DELETE]<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;graphql<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Type of GraphQL.<\/td>\n<\/tr>\n<tr style=\"height: 70px;\">\n<td style=\"height: 70px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;graphql.operation<\/strong><\/span><\/td>\n<td style=\"height: 70px; width: 70.5%;\" width=\"58%\">GraphQL operation to be supported for stored procedure. Valid operations are: [Query, Mutation]<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;fields.include<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Fields that are allowed access to permission.<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;fields.exclude<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Fields that are excluded from the action lists.<\/td>\n<\/tr>\n<tr style=\"height: 70px;\">\n<td style=\"height: 70px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;policy-request<\/strong><\/span><\/td>\n<td style=\"height: 70px; width: 70.5%;\" width=\"58%\">Specify the rule to be checked before sending any request to the database.<\/td>\n<\/tr>\n<tr style=\"height: 70px;\">\n<td style=\"height: 70px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;policy-database<\/strong><\/span><\/td>\n<td style=\"height: 70px; width: 70.5%;\" width=\"58%\">Specify an OData style filter rule that will be injected in the query sent to the database.<\/td>\n<\/tr>\n<tr style=\"height: 95px;\">\n<td style=\"height: 95px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>\u00a0 -c, &#8211;config<\/strong><\/span><\/td>\n<td style=\"height: 95px; width: 70.5%;\" width=\"58%\">Path to config file. Defaults to &#8216;dab-config.json&#8217; unless &#8216;dab-config.&lt;DAB_ENVIRONMENT&gt;.json&#8217; exists, where DAB_ENVIRONMENT is an environment variable.<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;help<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Display this help screen.<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>&#8211;version<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Display version information.<\/td>\n<\/tr>\n<tr style=\"height: 44px;\">\n<td style=\"height: 44px; width: 28.5%;\" width=\"41%\"><span style=\"font-family: 'courier new', courier, monospace;\"><strong>\u00a0 Entity (pos. 0)<\/strong><\/span><\/td>\n<td style=\"height: 44px; width: 70.5%;\" width=\"58%\">Name of the entity.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Minimal syntax<\/h3>\n<p>It doesn&#8217;t take much to add a table to the Data API builder configuration file. The basics are its name, table schema including keys, and permissions. Here&#8217;s how we add the <strong>authors<\/strong> table.<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab add \"authors\" --source \"[dbo].[authors]\" --source.type \"table\" --source.key-fields \"id\" --permissions \"anonymous:*\"<\/code><\/pre>\n<p>The resulting configuration looks like this:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">  \"entities\": {\r\n    \"authors\": {\r\n      \"source\": {\r\n        \"object\": \"[dbo].[authors]\",\r\n        \"type\": \"table\",\r\n        \"key-fields\": [ \"id\" ]\r\n      },\r\n      \"graphql\": {\r\n        \"enabled\": true,\r\n        \"type\": {\r\n          \"singular\": \"authors\",\r\n          \"plural\": \"authors\"\r\n        }\r\n      },\r\n      \"rest\": { \"enabled\": true },\r\n      \"permissions\": [\r\n        {\r\n          \"role\": \"anonymous\",\r\n          \"actions\": [ { \"action\": \"*\" } ]\r\n        }\r\n      ]\r\n    }\r\n  }<\/code><\/pre>\n<p>That&#8217;s a lot for a little. And more could be added; but for now, let&#8217;s make this simple. It&#8217;s worth pointing out that regardless of the backend database, the Data API builder configuration syntax is identical &#8211; you don&#8217;t need to do anything special to account for your backend data source. So far we&#8217;ve added the <strong>authors<\/strong> table, now let&#8217;s add <strong>series<\/strong>, <strong>books<\/strong>, and the cross-reference table: <strong>books_authors<\/strong>.<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab add \"authors\" --source \"[dbo].[authors]\" --source.type \"table\" --source.key-fields \"id\" --permissions \"anonymous:*\"\r\n\r\ndab add \"series\" --source \"[dbo].[series]\" --source.type \"table\" --source.key-fields \"id\" --permissions \"anonymous:*\"\r\n\r\ndab add \"books\" --source \"[dbo].[books]\" --source.type \"table\" --source.key-fields \"id\" --permissions \"anonymous:*\"\r\n\r\ndab add \"books_authors\" --source \"[dbo].[books_authors]\" --source.type \"table\" --source.key-fields \"book_id,author_id\" --permissions \"anonymous:*\" --graphql false<\/code><\/pre>\n<p>In the sample above, each table uses the same CLI syntax to get into the configuration file. Run this twice and you will get an error that the entities are already defined. If you want to modify an existing entity, use <code class=\"language-default\">update<\/code> instead of\u00a0<code class=\"language-default\">add<\/code>.<\/p>\n<h3>Hiding tables<\/h3>\n<p>However, if you look closely the last line is different. There is one extra flag <code class=\"language-default\">--graphql false<\/code> added to the <strong>books_authors<\/strong> table. Why? Setting\u00a0<code class=\"language-default\">--graphql<\/code>to <strong>false<\/strong> tells the Data API builder engine to hide the table from the graph schema. Why? The graph schema tells the consumer what entities it can query &#8211; including intellisense in debugging tools &#8211; and there is no practical reason to encourage consumers to directly query a cross-reference table. To be clear, this doesn&#8217;t mean we can&#8217;t use hidden entities in relationship definitions. What it means is that our graph schema is nice and clean.<\/p>\n<p><strong>A note about relationships in Data API builder<\/strong><\/p>\n<p>A part of you may wonder, why do I need to define my relationships when they are already defined in my database? That&#8217;s a fair question. First, let me remind you that a RDMS supports relationships but does not require them. That is to say, relationships in a database like SQL Server help ensure data integrity, but do not actually come into play when you perform JOIN statements in your query. The practical reason for relationship definitions in Data API builder is so you can customize them, naming them how you want them to appear in your queries and limit relationships you don&#8217;t want to present.<\/p>\n<h3>One-to-many &amp; many-to-one relationships<\/h3>\n<p>There is one series with many books in it. For example, Isaac Asimov&#8217;s Foundation series has some seven books from <em>Foundation<\/em> all thew way to <em>Forward the Foundation<\/em>. This, and its corollary many-to-one are the simplest relationships, showing up in almost every RDBM schema.<\/p>\n<p><a style=\"font-weight: bold; font-size: inherit; background-color: #f7f7f9; text-align: var(--bs-body-text-align);\" href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-one.jpg\"><img decoding=\"async\" class=\"wp-image-2753 size-full\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-one.jpg\" alt=\"Image dab many to one\" width=\"736\" height=\"529\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-one.jpg 736w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-one-300x216.jpg 300w\" sizes=\"(max-width: 736px) 100vw, 736px\" \/><\/a><\/p>\n<p><span style=\"font-size: 1rem; text-align: var(--bs-body-text-align);\">The image above highlights the series to book relationship. This is a one-to-many relationship when we consider<strong> series-to-books<\/strong>. It is a many-to-one relationship when we consider<strong> books-to-series<\/strong>. Let&#8217;s see what is required for us to add this to the Data API builder configuration file using the CLI.\u00a0<\/span><\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab update \"series\" --relationship \"books\" --target.entity \"series\" --cardinality many --relationship.fields \"id:series_id\"<\/code><\/pre>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab update \"books\" --relationship \"series\" --target.entity \"series\" --cardinality one --relationship.fields \"series_id:id\"<\/code><\/pre>\n<p>The first defines <strong>series-to-books<\/strong> and the second defines<strong> books-to-series<\/strong>. In both cases we identify the primary key and the foreign keys relevant to the relationship. When the result of the relationship (with the target table) is zero or more, we set the cardinality to many. When the result of the relationship (with the target table) is zero or one, we set the cardinality to one. Relationships, don&#8217;t forget, are exposed through Data API builder GraphQL endpoints. Relationship definitions do not impact REST endpoints.<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">\"relationships\": {\r\n  \"books\": {\r\n    \"cardinality\": \"many\",\r\n    \"target.entity\": \"series\",\r\n    \"source.fields\": [ \"id\" ],\r\n    \"target.fields\": [ \"series_id\" ]\r\n  }\r\n}<\/code><\/pre>\n<p>The relationship section of the entity is added automatically, perfectly formatted and ready for the Data API builder engine to start. If you look at it, it&#8217;s pretty simple. That said, notice how compound keys are supported by arrays, this and other features make Data API builder perfect for even the most complicated data schema.<\/p>\n<h3>Many-to-many<\/h3>\n<p>What makes many-to-many relationships tricky is that it requires a third table, usually referred to as a cross-reference or linking table. They typically have the key(s) for each of the two outside tables, and sometimes columns for data to describe relationship-specific data.<\/p>\n<p><a style=\"font-weight: bold; font-size: inherit; background-color: #f7f7f9; text-align: var(--bs-body-text-align);\" href=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-many.jpg\"><img decoding=\"async\" class=\"alignnone wp-image-2752 size-full\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-many.jpg\" alt=\"Image dab many to many\" width=\"778\" height=\"502\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-many.jpg 778w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-many-300x194.jpg 300w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/12\/dab-many-to-many-768x496.jpg 768w\" sizes=\"(max-width: 778px) 100vw, 778px\" \/><\/a><\/p>\n<p>In the case of a relational database, the resulting SQL required to query this relationship would have a minimum of two JOIN statements to connect the tables. Data API builder does this for you. All you need to do is to ensure the linking table is already referenced in the configuration file. However, as we noted above, the linking table entities never need to be exposed directly through the Grap schema.<\/p>\n<p>For our database a <strong>book<\/strong> can be written by many <strong>authors<\/strong>. At the same time, an <strong>author<\/strong> can write several <strong>books<\/strong>. <a href=\"https:\/\/github.com\/Azure-Samples\/data-api-builder\">That&#8217;s the classic scenario<\/a> for a <strong>many-to-many<\/strong> relationship. Here <strong>books_authors<\/strong> is the cross-reference table holding the primary key of the <strong>author<\/strong> and the primary key of the <strong>book<\/strong>. This is our linking table and what we include in our CLI command to build out the configuration.<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">dab update \"books\" --relationship \"authors\" --target.entity \"authors\" --cardinality many --linking.object \"dbo.books_authors\" --linking.source.fields \"book_id\" --linking.target.fields \"author_id\" \r\n\r\ndab update \"authors\" --relationship \"books\" --target.entity \"books\" --cardinality many --linking.object \"dbo.books_authors\" --linking.source.fields \"author_id\" --linking.target.fields \"book_id\"<\/code><\/pre>\n<p>A few things are removed, and a few things are added. Look at the syntax closely and the <code class=\"language-default\">--relationship:fields<\/code> we saw in our previous example has been removed. That&#8217;s because the Data API builder engine can infer those with other data you have already provided. Also notice that the linking table is listed specifically. This entity must already exist in the configuration file, but, as we mentioned above, it does not have to be exposed explicitly through the GraphQL endpoint.<\/p>\n<h3>Intuitive &amp; readable<\/h3>\n<p>Without a doubt, this short syntax is simpler than the SQL required to execute it. But let&#8217;s take a minute to step through a few important parts. Note the name of the first relationship is &#8220;<em>authors<\/em>&#8221; and the second is &#8220;<em>books<\/em>&#8220;. These appear in the graph query, so that <strong>books { authors }<\/strong> and <strong>authors { books }<\/strong> keeps your query both <a href=\"https:\/\/youtu.be\/XQRO_uoGhp4\">intuitive and readable<\/a>.<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">\"authors\": {\r\n  \"cardinality\": \"many\",\r\n  \"target.entity\": \"authors\",\r\n  \"linking.object\": \"dbo.books_authors\",\r\n  \"linking.source.fields\": [ \"book_id\" ],\r\n  \"linking.target.fields\": [ \"author_id\" ]\r\n}<\/code><\/pre>\n<p>The configuration for <strong>many-to-many<\/strong> relationships is simple enough, the CLI is your best bet to get it right the first time. Can you add it manually into the JSON? Yes. Can you edit the JSON after running the CLI? Yes. The CLI is a helper, not a constraint. You do you.<\/p>\n<h3>GraphQL queries<\/h3>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">query {\r\n    series {\r\n        items {\r\n            name\r\n            books {\r\n                items {\r\n                    title\r\n                }\r\n            }\r\n        }\r\n    }\r\n    books {\r\n        items {\r\n            title\r\n            series {\r\n                name\r\n            }\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<p>This query exercises both the series <strong>one-to-many<\/strong> relationship to books and the books <strong>many-to-one<\/strong> relationship to series. Look and how clean the Data API builder&#8217;s endpoint implementations are and how simple it can be for developers to access complex data. Now, let&#8217;s query the <strong>many-to-many<\/strong> relationship between <strong>authors<\/strong> and <strong>books<\/strong>.<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">query {\r\n    series {\r\n        items {\r\n            name\r\n            books {\r\n                items {\r\n                    title\r\n                    pages\r\n                    authors {\r\n                        items {\r\n                            first_name\r\n                            last_name\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<h3>Wrapping up<\/h3>\n<p>Using the Data Api builder CLI to constructor a configuration file that describes your tables, views, and stored procedures it all you need to get REST and GraphQL endpoints running against your MySQL, Cosmos DB, Progres and Azure SQL databases. But with a little more, you can quite easily define relationships between entities and make your GraphQL queries rich and capable.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Data API builder exposes REST endpoints for MySQL, PostgreSQL, Cosmos DB, SQL Server and Azure SQL. REST (Representational State Transfer) endpoints allow developers to easily query a single table, view or stored procedure. However, Data API builder also exposes GraphQL endpoints. Like REST, GraphQL returns data, but unlike REST, GraphQL can return data from multiple [&hellip;]<\/p>\n","protected":false},"author":96788,"featured_media":2563,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2751","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sql"],"acf":[],"blog_post_summary":"<p>Data API builder exposes REST endpoints for MySQL, PostgreSQL, Cosmos DB, SQL Server and Azure SQL. REST (Representational State Transfer) endpoints allow developers to easily query a single table, view or stored procedure. However, Data API builder also exposes GraphQL endpoints. Like REST, GraphQL returns data, but unlike REST, GraphQL can return data from multiple [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/2751","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=2751"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/2751\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/2563"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=2751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=2751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=2751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}