{"id":10747,"date":"2025-07-28T06:00:20","date_gmt":"2025-07-28T13:00:20","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cosmosdb\/?p=10747"},"modified":"2025-07-23T11:13:55","modified_gmt":"2025-07-23T18:13:55","slug":"scaling-multi-tenant-go-applications-choosing-the-right-database-partitioning-approach","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cosmosdb\/scaling-multi-tenant-go-applications-choosing-the-right-database-partitioning-approach\/","title":{"rendered":"Scaling multi-tenant Go applications: Choosing the right database partitioning approach"},"content":{"rendered":"<p>Multi-tenant applications face a fundamental challenge: how to efficiently store and query data for tenants of vastly different sizes? Consider the typical scenario where your platform serves both enterprise clients with hundreds of thousands of users, as well as small businesses with just a handful. With traditional database partitioning strategies you are likely to run into these common issues:<\/p>\n<ul>\n<li><strong>Partition imbalance<\/strong>: Large tenants create oversized partitions while small tenants waste allocated resources<\/li>\n<li><strong>Hot partitions<\/strong>: High-activity tenants overwhelm individual database partitions, creating performance bottlenecks<\/li>\n<li><strong>Inefficient queries<\/strong>: User-specific lookups require scanning entire tenant datasets<\/li>\n<li><strong>Resource contention<\/strong>: Mixed workloads compete for the same database resources<\/li>\n<\/ul>\n<p>Azure Cosmos DB has been a go-to solution for\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/architecture\/guide\/multitenant\/service\/cosmos-db\" target=\"_blank\" rel=\"noopener noreferrer\">multi-tenant applications<\/a>\u00a0due to its global distribution, automatic scaling, and flexible data models. Its partition-based architecture naturally aligns with tenant isolation requirements, making it attractive for SaaS platforms, IoT applications, and content management systems.<\/p>\n<p>However, even with these capabilities, the fundamental multi-tenant partitioning challenges persist.\u00a0This blog post examines how these issues might manifest and explores an approach to solving multi-tenant scaling challenges in Go applications using Azure Cosmos DB. You&#8217;ll learn how to implement this using the <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/cosmos-db\/nosql\/sdk-go\" target=\"_blank\" rel=\"noopener noreferrer\">Go SDK for Azure Cosmos DB<\/a>, focusing on how to achieve efficient data distribution and query performance.<\/p>\n<p><div class=\"alert alert-primary\">Check the <a href=\"https:\/\/github.com\/abhirockzz\/cosmosdb-go-hierarchical-partition-keys\">GitHub repository<\/a> for the code examples used in this blog<\/div><\/p>\n<h2>Challenges with a multi-tenant SaaS solution<\/h2>\n<p>Imagine you&#8217;re building a multi-tenant SaaS platform that manages user sessions and activities across different organizations using Azure Cosmos DB. In such a setup, tenant variability is a significant challenge. Enterprise clients may have over 50,000 users generating millions of session events, while small businesses might only have 10 to 50 users with minimal activity. Mid-market companies typically fall in between, with 500 to 5,000 users and moderate usage. This wide range of tenant sizes and activity levels creates unique challenges for data partitioning and resource allocation in the database.<\/p>\n<p>This is how you might define your user session data model using a single partition key:<\/p>\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">type UserSession struct {\r\n    ID        string    `json:\"id\"`\r\n    TenantID  string    `json:\"tenantId\"`     \/\/ Single partition key\r\n    UserID    string    `json:\"userId\"`\r\n    SessionID string    `json:\"sessionId\"`\r\n    Activity  string    `json:\"activity\"`\r\n    Timestamp time.Time `json:\"timestamp\"`\r\n}<\/code><\/pre>\n<p>This approach has several challenges. First, partition size imbalance occurs as enterprise tenants generate massive 20GB+ partitions, while small tenants use minimal storage, resulting in uneven resource utilization across physical partitions. Second, hot partition bottlenecks can develop when large tenants reach the\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/cosmos-db\/partitioning-overview#physical-partitions\" target=\"_blank\" rel=\"noopener noreferrer\">10,000 RU\/s physical partition limit<\/a>\u00a0during peak usage periods. Third, user queries become inefficient because looking up individual user sessions requires scanning entire tenant partitions, which consumes unnecessary Request Units. Cross-tenant analytics also suffer, as queries spanning multiple tenants become expensive cross-partition operations.<\/p>\n<h2>Hierarchical Partition Keys to the rescue<\/h2>\n<p>Hierarchical partition keys (HPKs) help implement subpartitioning that allows you to define up to three levels of partition key hierarchy. This leads to better data distribution and query routing compared to traditional single-level partitioning. Instead of forcing all tenant data into a single partition boundary, you are able to create logical subdivisions that align with your actual access patterns.<\/p>\n<p>Mapping this to the the multi-tenant solution challenges, hierarchical partition keys allow you to define a three-level partitioning scheme:<\/p>\n<ul>\n<li><strong>Level 1<\/strong>: Primary partition key (e.g.,\u00a0<code>tenantId<\/code>) &#8211; provides tenant isolation<\/li>\n<li><strong>Level 2<\/strong>: Secondary partition key (e.g.,\u00a0<code>userId<\/code>) &#8211; distributes data within tenants<\/li>\n<li><strong>Level 3<\/strong>: Tertiary partition key (e.g.,\u00a0<code>sessionId<\/code>) &#8211; provides fine-grained distribution<\/li>\n<\/ul>\n<p>This creates a logical partition path like instead of just\u00a0<code>[\"Enterprise-Corp\"]<\/code>. Large tenants can be subdivided by user and session, eliminating hot partitions. Instead of one massive &#8220;Enterprise-Corp&#8221; partition, you get manageable partitions like:\u00a0<code>[\"Enterprise-Corp\", \"user-1001\", \"session-abc123\"]<\/code>,\u00a0<code>[\"Enterprise-Corp\", \"user-1002\", \"session-def456\"]<\/code>, etc.<\/p>\n<p>Now, we can refactor the user session data model as such:<\/p>\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">type UserSession struct {\r\n    ID        string    `json:\"id\"`\r\n    TenantID  string    `json:\"tenantId\"`     \/\/ Level 1: Tenant isolation\r\n    UserID    string    `json:\"userId\"`      \/\/ Level 2: User distribution\r\n    SessionID string    `json:\"sessionId\"`   \/\/ Level 3: Session granularity\r\n    Activity  string    `json:\"activity\"`\r\n    Timestamp time.Time `json:\"timestamp\"`\r\n}\r\n<\/code><\/pre>\n<p>Your queries can now be efficiently routed to only the subset of physical partitions that contain the relevant data. Specifying the full or partial subpartitioned partition key path effectively avoids a cross-partition query across all the parititions, which is a common problem with single partition keys.<\/p>\n<ul>\n<li><strong>Session details<\/strong>:\u00a0<code>WHERE tenantId = 'Enterprise-Corp' AND userId = 'user-1001' AND sessionId = 'session-abc123'<\/code>\u00a0provides single-partition access<\/li>\n<li><strong>User-specific queries<\/strong>:\u00a0<code>WHERE tenantId = 'Enterprise-Corp' AND userId = 'user-1001'<\/code>\u00a0pinpoints exact data location<\/li>\n<li><strong>Tenant-wide queries<\/strong>:\u00a0<code>WHERE tenantId = 'Enterprise-Corp'<\/code>\u00a0only targets relevant partitions<\/li>\n<\/ul>\n<p>Each logical partition (tenant-user-session combination) can scale independently, allowing tenant data to exceed the traditional 20GB limit and maintain optimal performance. Targeted queries consume fewer Request Units by avoiding unnecessary cross-partition scans, directly reducing operational expenses.<\/p>\n<h2>Hierarchical Partition Keys in action with the Go SDK for Azure Cosmos DB<\/h2>\n<p>To explore the concepts, we will use\u00a0<a href=\"https:\/\/github.com\/abhirockzz\/cosmosdb-go-hierarchical-partition-keys\" target=\"_blank\" rel=\"noopener noreferrer\">a Go application<\/a>\u00a0that loads sample user session data into Azure Cosmos DB and queries it using the hierarchical partition keys.<\/p>\n<h3><a href=\"https:\/\/dev.to\/abhirockzz\/scaling-multi-tenant-go-applications-choosing-the-right-database-partitioning-approach-2amd#load-data-into-cosmos-db\" name=\"load-data-into-cosmos-db\"><\/a>Load data into Azure Cosmos DB<\/h3>\n<p>Run the loader to populate the database with sample data that uses hierarchical partition keys. Its a\u00a0<a href=\"https:\/\/github.com\/abhirockzz\/cosmosdb-go-hierarchical-partition-keys\/blob\/main\/load\/main.go\" target=\"_blank\" rel=\"noopener noreferrer\">CLI application<\/a> that generates user session data for users in different tenant types (Enterprise, Mid-market, Small business) and inserts it into the Azure Cosmos DB container.<\/p>\n<p>Clone the repository and change into the\u00a0<code>load<\/code>\u00a0directory:<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">git clone https:\/\/github.com\/abhirockzz\/cosmosdb-go-hierarchical-partition-keys\r\n\r\ncd cosmosdb-go-hierarchical-partition-keys\/load<\/code><\/pre>\n<p>Build the data loader application and run it. The database and container will be created automatically if they do not exist.<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">go build -o data-loader main.go\r\n\r\n.\/data-loader -rows 100 -database &lt;insert database name&gt; -container &lt;insert container name&gt; -endpoint \"https:\/\/your-account.documents.azure.com:443\/\"<\/code><\/pre>\n<p>Here is the code snippet demonstrating how the container is created with hierarchical partition keys:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">\/\/...\r\npartitionKeyDef := azcosmos.PartitionKeyDefinition{\r\n    Kind:    azcosmos.PartitionKeyKindMultiHash,\r\n    Version: 2, \/\/ Version 2 is required for hierarchical partition keys\r\n    Paths: []string{\r\n        \"\/tenantId\",  \/\/ Level 1: Tenant isolation\r\n        \"\/userId\",    \/\/ Level 2: User distribution\r\n        \"\/sessionId\", \/\/ Level 3: Session granularity\r\n    },\r\n}\r\n\r\n\/\/ Create container properties\r\ncontainerProperties := azcosmos.ContainerProperties{\r\n    ID:                     containerName,\r\n    PartitionKeyDefinition: partitionKeyDef,\r\n}\r\n\r\n\/\/ Create container with 400 RU\/s throughput\r\nthroughputProperties := azcosmos.NewManualThroughputProperties(400)\r\n\r\n_, err = databaseClient.CreateContainer(ctx, containerProperties, &amp;azcosmos.CreateContainerOptions{\r\n    ThroughputProperties: &amp;throughputProperties,\r\n})\r\n\/\/....\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/data\/azcosmos#ContainerClient.UpsertItem\">UpsertItem<\/a> is used to add data:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">\/\/ Create hierarchical partition key (TenantID, UserID, SessionID)\r\npartitionKey := azcosmos.NewPartitionKeyString(session.TenantID).\r\n    AppendString(session.UserID).\r\n    AppendString(session.SessionID)\r\n\r\n\/\/ Insert the record using UpsertItem (insert or update if exists)\r\n_, err = containerClient.UpsertItem(ctx, partitionKey, sessionJSON, nil)\r\n<\/code><\/pre>\n<\/div>\n<p>Lets dive into the queries that demonstrate how to retrieve data using hierarchical partition keys.<\/p>\n<h3>Query patterns<\/h3>\n<p>Let&#8217;s examine how different query patterns perform with hierarchical partition keys. To execute these examples, you can comment out the relevant sections in the\u00a0<code>main<\/code>\u00a0function of the\u00a0<a href=\"https:\/\/github.com\/abhirockzz\/cosmosdb-go-hierarchical-partition-keys\/blob\/main\/query\/main.go\" target=\"_blank\" rel=\"noopener noreferrer\">query\/main.go<\/a>\u00a0file, set the required environment variables, and run the application.<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">export COSMOS_DB_ENDPOINT=https:\/\/your-account.documents.azure.com:443\/\r\nexport COSMOS_DB_DATABASE_NAME=&lt;insert database name&gt;\r\nexport COSMOS_DB_CONTAINER_NAME=&lt;insert container name&gt;\r\n\r\ncd cosmosdb-go-hierarchical-partition-keys\/query\r\n\r\ngo run main.go<\/code><\/pre>\n<h4>1. Point Read<\/h4>\n<p>This is the most efficient query type, where you retrieve a single item using its unique ID and full partition key path. This avoids any cross-partition overhead.<\/p>\n<p>Take a look at the\u00a0<code>executePointRead<\/code>\u00a0function that performs a point read operation:<\/p>\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">func executePointRead(id, tenantId, userId, sessionId string) {\r\n    \/\/ Create a partition key using the full partition key values\r\n    pk := azcosmos.NewPartitionKeyString(tenantId).AppendString(userId).AppendString(sessionId)\r\n\r\n    \/\/ Perform a point read operation\r\n    resp, err := container.ReadItem(context.Background(), pk, id, nil)\r\n    if err != nil {\r\n        log.Fatalf(\"Failed to read item: %v\", err)\r\n    }\r\n\r\n    var queryResult QueryResult\r\n    err = json.Unmarshal(resp.Value, &amp;queryResult)\r\n    \/\/.....\r\n}<\/code><\/pre>\n<h4>2. Session-Specific Data<\/h4>\n<p>This query is routed to the single logical and physical partition that contains the data for the specified values of <code>tenantId<\/code>,\u00a0<code>tenantId<\/code>, and\u00a0<code>sessionId<\/code>.<\/p>\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">func queryWithFullPartitionKey(tenantID, userID, sessionID string) {\r\n    query := \"SELECT * FROM c WHERE c.tenantId = @tenantId AND c.userId = @userId AND c.sessionId = @sessionId\"\r\n\r\n    pkFull := azcosmos.NewPartitionKeyString(tenantID).AppendString(userID).AppendString(sessionID)\r\n\r\n    pager := container.NewQueryItemsPager(query, pkFull, &amp;azcosmos.QueryOptions{\r\n        QueryParameters: []azcosmos.QueryParameter{\r\n            {Name: \"@tenantId\", Value: tenantID},\r\n            {Name: \"@userId\", Value: userID},\r\n            {Name: \"@sessionId\", Value: sessionID},\r\n        },\r\n    })\r\n\r\n    for pager.More() {\r\n        page, err := pager.NextPage(context.Background())\r\n        if err != nil {\r\n            log.Fatal(err)\r\n        }\r\n        for _, _item := range page.Items {\r\n            var queryResult QueryResult\r\n            err = json.Unmarshal(_item, &amp;queryResult)\r\n            \/\/ log the results\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<h4>3. User-Specific Data (Targeted Cross-Partition)<\/h4>\n<p>This is a targeted cross-partition query that returns data for a specific user in the tenant and routed to specific subset of logical and physical partition(s) that contain data for the specified values of <code>tenantId<\/code>\u00a0and\u00a0<code>userId<\/code>.<\/p>\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">func queryWithTenantAndUserID(tenantID, userID string) {\r\n    query := \"SELECT * FROM c WHERE c.tenantId = @tenantId AND c.userId = @userId\"\r\n\r\n    \/\/ since we don't have the full partition key, we use an empty partition key\r\n    emptyPartitionKey := azcosmos.NewPartitionKey()\r\n\r\n    pager := container.NewQueryItemsPager(query, emptyPartitionKey, &amp;azcosmos.QueryOptions{\r\n        QueryParameters: []azcosmos.QueryParameter{\r\n            {Name: \"@tenantId\", Value: tenantID},\r\n            {Name: \"@userId\", Value: userID},\r\n        },\r\n    })\r\n\r\n    for pager.More() {\r\n        page, err := pager.NextPage(context.Background())\r\n        if err != nil {\r\n            log.Fatal(err)\r\n        }\r\n\r\n        fmt.Println(\"==========================================\")\r\n\r\n        for _, _item := range page.Items {\r\n            var queryResult QueryResult\r\n            err = json.Unmarshal(_item, &amp;queryResult)\r\n            \/\/ log the results\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<h4>4. Tenant-Wide Data (Efficient Cross-Partition)<\/h4>\n<p>This is a targeted cross-partition query that returns data for all users in a tenant and routed to a specific subset of logical and physical partition(s) that contain data for the specified value of <code>tenantId<\/code>.<\/p>\n<p>The\u00a0<code>queryWithSinglePKParameter<\/code> is a function that lets you query with a single partition key parameter \u2013 this can be either <code>tenantId<\/code>,\u00a0<code>userId<\/code>, or\u00a0<code>sessionId<\/code>.<\/p>\n<pre class=\"prettyprint language-go\"><code class=\"language-go\">func queryWithSinglePKParameter(paramType, paramValue string) {\r\n    if paramType != \"tenantId\" &amp;&amp; paramType != \"userId\" &amp;&amp; paramType != \"sessionId\" {\r\n        log.Fatalf(\"Invalid parameter type: %s\", paramType)\r\n    }\r\n\r\n    query := fmt.Sprintf(\"SELECT * FROM c WHERE c.%s = @param\", paramType)\r\n    emptyPartitionKey := azcosmos.NewPartitionKey()\r\n\r\n    pager := container.NewQueryItemsPager(query, emptyPartitionKey, &amp;azcosmos.QueryOptions{\r\n        QueryParameters: []azcosmos.QueryParameter{\r\n            {Name: \"@param\", Value: paramValue},\r\n        },\r\n    })\r\n\r\n    for pager.More() {\r\n        page, err := pager.NextPage(context.Background())\r\n        if err != nil {\r\n            log.Fatal(err)\r\n        }\r\n\r\n        fmt.Printf(\"Results for %s: %s\\n\", paramType, paramValue)\r\n        fmt.Println(\"==========================================\")\r\n\r\n        for _, _item := range page.Items {\r\n            var queryResult QueryResult\r\n            err = json.Unmarshal(_item, &amp;queryResult)\r\n            \/\/ log the results\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<h4>5. User or Session Across All Tenants (Fan-Out)<\/h4>\n<p>Both types of queries will be routed to all physical partitions, resulting in a fan-out cross-partition query.<\/p>\n<pre class=\"prettyprint language-sql\"><code class=\"language-sql\">SELECT * FROM c WHERE c.userId = 'user-1001'\r\nSELECT * FROM c WHERE c.sessionId = 'session-abc123'<\/code><\/pre>\n<p><div class=\"alert alert-warning\">This type of query is not efficient and should be avoided in production scenarios. It is included here for completeness, but you should design your application to avoid such queries whenever possible. <\/div><\/p>\n<h2>Conclusion<\/h2>\n<p>Multi-tenant applications face inherent scaling challenges with traditional single-level partitioning: tenant size variability, hot partitions, and inefficient query patterns that impact both performance and cost. Hierarchical partition keys in Azure Cosmos DB address these issues by enabling intelligent data distribution across multiple partition levels, maintaining tenant isolation while achieving better resource utilization. By aligning your partition strategy with actual access patterns, you can build applications that scale naturally with tenant growth while maintaining predictable performance characteristics.<\/p>\n<p>Check out the documentation for the <a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/data\/azcosmos\" target=\"_blank\" rel=\"noopener noreferrer\">azcosmos package<\/a>\u00a0(Go SDK). For more information on hierarchical partition keys, refer to the\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/cosmos-db\/hierarchical-partition-keys\" target=\"_blank\" rel=\"noopener noreferrer\">official documentation<\/a>.<\/p>\n<\/div>\n<div class=\"crayons-article__main \">\n<div class=\"js-billboard-container body-billboard-container\" data-async-url=\"\/abhirockzz\/scaling-multi-tenant-go-applications-choosing-the-right-database-partitioning-approach-2amd\/bmar11\/post_body_bottom\">\n<div>\n<h2>About Azure Cosmos DB<\/h2>\n<article id=\"post-10622\" class=\"middle-column pe-xl-198\" data-clarity-region=\"article\">\n<div class=\"entry-content sharepostcontent \" data-bi-area=\"body_article\" data-bi-id=\"post_page_body_article\">\n<p>Azure Cosmos DB is a fully managed and serverless distributed database for modern app development, with SLA-backed speed and availability, automatic and instant scalability, and support for open-source PostgreSQL, MongoDB, and Apache Cassandra. To stay in the loop on Azure Cosmos DB updates, follow us on\u00a0<a href=\"https:\/\/twitter.com\/AzureCosmosDB\" target=\"_blank\" rel=\"noopener\">X<\/a>,\u00a0<a href=\"https:\/\/aka.ms\/AzureCosmosDBYouTube\" target=\"_blank\" rel=\"noopener\">YouTube<\/a>, and\u00a0<a href=\"https:\/\/www.linkedin.com\/company\/azure-cosmos-db\/\" target=\"_blank\" rel=\"noopener\">LinkedIn<\/a>.<\/p>\n<p>To easily build your first database, watch our\u00a0<a href=\"https:\/\/youtube.com\/playlist?list=PLmamF3YkHLoLLGUtSoxmUkORcWaTyHlXp\" target=\"_blank\" rel=\"noopener\">Get Started videos<\/a>\u00a0on YouTube and explore ways to\u00a0<a href=\"https:\/\/docs.microsoft.com\/azure\/cosmos-db\/optimize-dev-test\" target=\"_blank\" rel=\"noopener\">dev\/test free.<\/a><\/p>\n<\/div>\n<\/article>\n<\/div>\n<\/div>\n<\/div>\n<section id=\"comments\" class=\"text-padding mb-4 border-t-1 border-0 border-solid border-base-10\" data-follow-button-container=\"true\" data-updated-at=\"2025-07-16 05:05:13 UTC\">\n<header class=\"relative flex justify-between items-center mb-6\">\n<div class=\"flex items-center\"><\/div>\n<\/header>\n<\/section>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Multi-tenant applications face a fundamental challenge: how to efficiently store and query data for tenants of vastly different sizes? Consider the typical scenario where your platform serves both enterprise clients with hundreds of thousands of users, as well as small businesses with just a handful. With traditional database partitioning strategies you are likely to run [&hellip;]<\/p>\n","protected":false},"author":181737,"featured_media":10748,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[14,1828,1935],"tags":[499,1737],"class_list":["post-10747","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-core-sql-api","category-data-modeling","category-go-sdk","tag-azure-cosmos-db","tag-partitioning"],"acf":[],"blog_post_summary":"<p>Multi-tenant applications face a fundamental challenge: how to efficiently store and query data for tenants of vastly different sizes? Consider the typical scenario where your platform serves both enterprise clients with hundreds of thousands of users, as well as small businesses with just a handful. With traditional database partitioning strategies you are likely to run [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/10747","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/users\/181737"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/comments?post=10747"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/10747\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media\/10748"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media?parent=10747"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/categories?post=10747"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/tags?post=10747"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}