{"id":11688,"date":"2026-02-03T07:10:30","date_gmt":"2026-02-03T15:10:30","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cosmosdb\/?p=11688"},"modified":"2026-02-03T07:13:24","modified_gmt":"2026-02-03T15:13:24","slug":"part-2-building-a-python-crud-api-with-azure-functions-and-azure-cosmos-db","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cosmosdb\/part-2-building-a-python-crud-api-with-azure-functions-and-azure-cosmos-db\/","title":{"rendered":"Part 2: Building a Python CRUD API with Azure Functions and Azure Cosmos DB"},"content":{"rendered":"<h3><strong>Series: Building Serverless Applications with Azure Functions and Azure Cosmos DB<\/strong><\/h3>\n<p>In the<a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/building-your-first-serverless-http-api-on-azure-with-azure-functions-fastapi\/\"> first post of this series<\/a>, we focused on establishing the fundamentals of serverless architecture by building and deploying a simple HTTP API using Azure Functions and FastAPI. The post centred on serverless compute, showing how Azure Functions handles execution, scaling, and infrastructure management while FastAPI provides a modern, developer-friendly API framework.<\/p>\n<p>In this post, we extend that foundation by introducing serverless data. You\u2019ll build a Python-based CRUD inventory API and persist data using Azure Cosmos DB Serverless, learning how to securely connect to a NoSQL database, model and validate data, and structure clean CRUD operations while keeping the application fully serverless. By the end of this post, you\u2019ll understand how serverless compute and serverless data work together to form the core of a production-ready serverless application.<\/p>\n<h3>Posts in this series<\/h3>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/building-your-first-serverless-http-api-on-azure-with-azure-functions-fastapi\/\">Part 1: Building Your First Serverless HTTP API with Azure Functions and FastAPI<\/a> &#8211; Establishes the fundamentals of serverless architecture and serverless compute.<\/li>\n<\/ul>\n<h2>Prerequisites<\/h2>\n<p>Before starting, make sure you have:<\/p>\n<ul>\n<li><a href=\"https:\/\/azure.microsoft.com\/free\/\">An Azure account<\/a><\/li>\n<li>Python 3.10 or later<\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/azure-functions\/functions-run-local?tabs=windows%2Cisolated-process%2Cnode-v4%2Cpython-v2%2Chttp-trigger%2Ccontainer-apps&amp;pivots=programming-language-python\">Azure Functions Core Tools v4<\/a><\/li>\n<li>Completed <a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/building-your-first-serverless-http-api-on-azure-with-azure-functions-fastapi\/\">Part 1<\/a> of this series<\/li>\n<\/ul>\n<h2>What is Azure Cosmos DB?<\/h2>\n<p>Azure Cosmos DB is a fully managed, globally distributed NoSQL database designed for:<\/p>\n<ul>\n<li>Low latency<\/li>\n<li>Elastic scalability<\/li>\n<li>Serverless consumption<\/li>\n<\/ul>\n<p>It uses a schema-agnostic JSON document model, which makes it a great fit for application data such as product catalogs or inventories. Azure Cosmos DB also supports vector and hybrid search, enabling AI-driven use cases like RAG and agentic applications.<\/p>\n<p>In this tutorial, we\u2019ll use Cosmos DB Serverless, which automatically scales and charges only for the operations you perform ideal for serverless APIs.<\/p>\n<h2>Architecture Overview<\/h2>\n<p>At a high level:<\/p>\n<ol>\n<li><strong>Azure Functions<\/strong> provides the execution environment and HTTP trigger<\/li>\n<li><strong>FastAPI<\/strong> handles routing, validation, and API documentation<\/li>\n<li><strong>Azure Cosmos DB (Serverless)<\/strong> stores inventory data as JSON documents<\/li>\n<li><strong>Cosmos DB Python SDK<\/strong> is used for database interactions<\/li>\n<\/ol>\n<p>We intentionally use the Cosmos DB SDK instead of Azure Functions bindings. While bindings are great for event-driven workloads, SDK-based access gives us clearer control and flexibility for CRUD APIs.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/01\/Designer-1-1.png\"><img decoding=\"async\" class=\"aligncenter wp-image-11836 size-full\" src=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/01\/Designer-1-1.png\" alt=\"Architecture diagram showing a Python CRUD API flow. An HTTP POST request to \/api\/products goes to Azure Functions with FastAPI and Pydantic models for data validation. CRUD operations (Create, Read, Update, Delete) are handled using the Cosmos DB Python SDK, which interacts with Azure Cosmos DB (serverless) containing a ProductDatabase and ProductContainer.\" width=\"1536\" height=\"594\" srcset=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/01\/Designer-1-1.png 1536w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/01\/Designer-1-1-300x116.png 300w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/01\/Designer-1-1-1024x396.png 1024w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/01\/Designer-1-1-768x297.png 768w\" sizes=\"(max-width: 1536px) 100vw, 1536px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Our project structure will look like this:<\/p>\n<pre class=\"prettyprint language-default\"><code class=\"language-default\">project\/\r\n|\u2500\u2500 function_app.py\r\n|\u2500\u2500 db.py\r\n|\u2500\u2500 models.py\r\n|\u2500\u2500 crud.py\r\n|\u2500\u2500 routes.py\r\n|\u2500\u2500 requirements.txt<\/code><\/pre>\n<h2>Building the CRUD application<\/h2>\n<h3>Creating the Cosmos DB Account<\/h3>\n<p>Before writing application code, we need a place to store data. Create a <strong>Cosmos DB NoSQL API (Serverless)<\/strong> account using the Azure Portal. The official quickstart walks through this well:\n<a href=\"https:\/\/learn.microsoft.com\/azure\/cosmos-db\/quickstart-portal\">https:\/\/learn.microsoft.com\/azure\/cosmos-db\/quickstart-portal<\/a><\/p>\n<p>For this application:<\/p>\n<ol>\n<li>Create a serverless Cosmos DB NoSQL API account<\/li>\n<li>Create a database named ProductDatabase<\/li>\n<li>Create a container named ProductContainer<\/li>\n<li>Set the partition key to \/category.<\/li>\n<\/ol>\n<p>Choosing \/category as the partition key allows related products to be grouped logically and queried efficiently.<\/p>\n<h3>Connecting the Function App to Cosmos DB<\/h3>\n<p>A serverless app should not hard-code infrastructure details. Instead, we use environment variables to keep configuration separate from code.<\/p>\n<p>In <code>local.settings.json<\/code>, we store the Cosmos DB endpoint and container details:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">\"Values\": {\r\n\u00a0 \u00a0 \"FUNCTIONS_WORKER_RUNTIME\": \"python\",\r\n\u00a0 \u00a0 \"AzureWebJobsStorage\": \"UseDevelopmentStorage=true\",\r\n\u00a0 \u00a0 \"COSMOSDB_ENDPOINT\": \"https:\/\/&lt;cosmos-account&gt;.documents.azure.com:443\/\",\r\n\u00a0 \u00a0 \"COSMOSDB_DATABASE\": \"ProductDatabase\",\r\n\u00a0 \u00a0 \"COSMOSDB_CONTAINER\": \"ProductContainer\"\r\n\u00a0 }\r\n}<\/code><\/pre>\n<h3><strong>Installing<\/strong> Dependencies<\/h3>\n<p>Add the Cosmos DB SDK and Azure Identity packages to <code>requirements.txt<\/code>:<\/p>\n<pre><code>azure-cosmos&gt;=4.3.0\r\nazure-identity<\/code><\/pre>\n<h3>Connecting to Cosmos DB<\/h3>\n<p>Rather than using account keys, we authenticate to Cosmos DB using Managed Identity. This avoids secrets in configuration files and aligns with Azure security best practices.<\/p>\n<p>In <code>db.py<\/code>, we initialize the Cosmos client once and expose a helper to retrieve the container:<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">COSMOSDB_ENDPOINT = os.environ[\"COSMOSDB_ENDPOINT\"]\r\nDATABASE_NAME = os.environ.get(\"COSMOSDB_DATABASE\", \"ProductsDB\")\r\nCONTAINER_NAME = os.environ.get(\"COSMOSDB_CONTAINER\", \"ProductsContainer\")\r\n\r\ncredential = DefaultAzureCredential()\r\ncosmos_client = CosmosClient( COSMOSDB_ENDPOINT, credential, connection_mode=\"Gateway\",)\r\n\r\nasync def get_container() -&gt; ContainerProxy:\r\n\u00a0\u00a0\u00a0 database = cosmos_client.get_database_client(DATABASE_NAME)\r\n\u00a0\u00a0\u00a0 return database.get_container_client(CONTAINER_NAME)<\/code><\/pre>\n<p>Creating the client once improves performance and ensures connections are reused across requests.<\/p>\n<h3><strong>Modelling Inventory Data with Pydantic<\/strong><\/h3>\n<p>Before storing anything, we need to define <em>what a product looks like<\/em>.<\/p>\n<p>Using <strong>Pydantic<\/strong>, we define models that:<\/p>\n<ul>\n<li>Validate incoming requests<\/li>\n<li>Document the API automatically<\/li>\n<li>Provide a clear contract between layers<\/li>\n<\/ul>\n<p>The base Product model represents fields intrinsic to a product:<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">class Product(BaseModel):\r\n\u00a0\u00a0\u00a0 name: str = Field(min_length=1, max_length=255)\r\n\u00a0\u00a0\u00a0 description: Optional[str] = Field(None, max_length=1000)\r\n\u00a0\u00a0\u00a0 category: str = Field(min_length=1, max_length=100)\r\n\u00a0\u00a0\u00a0 price: Decimal = Field(gt=0)\r\n\r\n\u00a0\u00a0\u00a0 model_config = ConfigDict(extra=\"ignore\", str_strip_whitespace=True,)<\/code><\/pre>\n<p>From this base model, we derive:<\/p>\n<ul>\n<li>ProductCreate \u2014 what clients send when creating a product<\/li>\n<li>ProductResponse \u2014 what the API returns after persistence<\/li>\n<\/ul>\n<p>Separating these models keeps the API flexible as requirements evolve.<\/p>\n<p><strong>Create Model<\/strong><\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">class ProductCreate(Product):\r\n\u00a0 \u00a0 \"\"\"Fields required to create a product.\"\"\"\r\n    pass<\/code><\/pre>\n<p><strong>Response model<\/strong><\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">class ProductResponse(Product):\r\n    id: str \r\n\u00a0 \u00a0 _ts: int<\/code><\/pre>\n<h3>Implementing the Create Operation<\/h3>\n<p>With the data model in place, we can implement our first CRUD operation Create in <code>crud.py<\/code>.<\/p>\n<p>The responsibility of this layer is simple:<\/p>\n<ul>\n<li>Accept validated data<\/li>\n<li>Convert it into a Cosmos DB document<\/li>\n<li>Persist it using the SDK<\/li>\n<li>Return the stored document<\/li>\n<\/ul>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">async def create_product(container, product):\r\n\u00a0\u00a0\u00a0 product_doc = {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"id\": str(uuid4()),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"name\": product.name,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"description\": product.description,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"category\": product.category,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"price\": float(product.price),\r\n\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0 created_item = await container.create_item(body=product_doc)\r\n\u00a0\u00a0\u00a0 return ProductResponse.model_validate(created_item)<\/code><\/pre>\n<p>Cosmos DB stores numeric values as JSON numbers, which is why we convert Decimal to float before saving.<\/p>\n<h3><strong>Exposing the API with FastAPI Routes<\/strong><\/h3>\n<p>FastAPI acts as the HTTP boundary of the application. It:<\/p>\n<ul>\n<li>Parses incoming requests<\/li>\n<li>Validates data<\/li>\n<li>Maps HTTP calls to business logic<\/li>\n<\/ul>\n<p>In routes.py, we define a simple endpoint for product creation:<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">router = APIRouter()\r\n\r\n@router.post(\"\/products\", response_model=ProductResponse)\r\nasync def create_product_route(product: ProductCreate,\r\n\u00a0\u00a0\u00a0 container=Depends(get_container),):\r\n\u00a0\u00a0\u00a0 return await create_product(container, product)<\/code><\/pre>\n<p>This separation keeps HTTP concerns (routing, status codes) isolated from database logic.<\/p>\n<h3>Wiring Everything Together<\/h3>\n<p>Finally, we register the router with the FastAPI app inside the Azure Functions entry point:<\/p>\n<pre class=\"prettyprint language-py\"><code class=\"language-py\">FastAPI_app.include_router(router, prefix=\"\/api\")<\/code><\/pre>\n<p>At this point, the request flow is fully wired end to end.<\/p>\n<h2>Testing the API<\/h2>\n<p>Start the function locally:<\/p>\n<p><code><em>func start<\/em><\/code><\/p>\n<p>Send a POST request to \/api\/products:<\/p>\n<pre class=\"prettyprint language-json\"><code class=\"language-json\">{\r\n\u00a0 \"name\": \"TestProduct\",\r\n\u00a0 \"description\": \"This is a test product\",\r\n\u00a0 \"category\": \"Footwear\",\r\n\u00a0 \"price\": 10.0\r\n}<\/code><\/pre>\n<p>If successful, the API returns the created product along with system-generated metadata from Cosmos DB.<\/p>\n<h2>Wrapping Up<\/h2>\n<p>In this post, we extended our serverless API by introducing persistence using <strong>Azure Cosmos DB<\/strong>. Along the way, we explored:<\/p>\n<ul>\n<li>Why Cosmos DB fits serverless workloads<\/li>\n<li>How to connect securely using Managed Identity<\/li>\n<li>How to model data cleanly with Pydantic<\/li>\n<li>How to structure CRUD logic and API routes<\/li>\n<\/ul>\n<p>More importantly, we built a foundation that scales naturally as the application grows.<\/p>\n<h2>What\u2019s Next?<\/h2>\n<p>In the next post, we\u2019ll move beyond request-response APIs and explore <strong>event-driven serverless design<\/strong> using the <strong>Cosmos DB Change Feed<\/strong> with Azure Functions triggers allowing our application to react automatically to data changes.<\/p>\n<h2>Resources<\/h2>\n<ul>\n<li>GitHub sample: <a href=\"https:\/\/github.com\/Azure-Samples\/serverless-python-labs\/tree\/solutions\/solutions\/lab2\">Build Python CRUD API with Azure Functions and Azure Cosmos DB<\/a><\/li>\n<li>Using Azure Cosmos DB with Azure Functions: <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/azure-functions\/functions-add-output-binding-cosmos-db-vs-code?pivots=programming-language-python\">Connect Azure Functions to Azure Cosmos DB using Visual Studio Code | Microsoft Learn<\/a><\/li>\n<li>Azure Cosmos DB Python Quickstart:\u00a0 <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/cosmos-db\/quickstart-python\">Quickstart &#8211; Azure SDK for Python &#8211; Azure Cosmos DB | Microsoft Learn<\/a><\/li>\n<li>Learn more about Azure Cosmos DB: <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/cosmos-db\/\">Azure Cosmos DB documentation &#8211; Azure Cosmos DB | Microsoft Learn<\/a><\/li>\n<\/ul>\n<h3 id=\"about-azure-cosmos-db\"><strong>About Azure Cosmos DB<\/strong><\/h3>\n<p>Azure Cosmos DB is a fully managed and serverless NoSQL and vector database for modern app development, including AI applications. With its SLA-backed speed and availability as well as instant dynamic scalability, it is ideal for real-time NoSQL and MongoDB applications that require high performance and distributed computing over massive volumes of NoSQL and vector data.<\/p>\n<p>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","protected":false},"excerpt":{"rendered":"<p>Series: Building Serverless Applications with Azure Functions and Azure Cosmos DB In the first post of this series, we focused on establishing the fundamentals of serverless architecture by building and deploying a simple HTTP API using Azure Functions and FastAPI. The post centred on serverless compute, showing how Azure Functions handles execution, scaling, and infrastructure [&hellip;]<\/p>\n","protected":false},"author":90111,"featured_media":11839,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[14,1217],"tags":[496,1312,1177],"class_list":["post-11688","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-core-sql-api","category-python-sdk","tag-azure-functions","tag-python","tag-serverless"],"acf":[],"blog_post_summary":"<p>Series: Building Serverless Applications with Azure Functions and Azure Cosmos DB In the first post of this series, we focused on establishing the fundamentals of serverless architecture by building and deploying a simple HTTP API using Azure Functions and FastAPI. The post centred on serverless compute, showing how Azure Functions handles execution, scaling, and infrastructure [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/11688","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\/90111"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/comments?post=11688"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/11688\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media\/11839"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media?parent=11688"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/categories?post=11688"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/tags?post=11688"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}