<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Manuel Kanetscheider </title>
    <description>The latest articles on Forem by Manuel Kanetscheider  (@manukanne).</description>
    <link>https://forem.com/manukanne</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F680439%2F39de02b9-c129-42a3-a6f1-bf6582c39315.jpg</url>
      <title>Forem: Manuel Kanetscheider </title>
      <link>https://forem.com/manukanne</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/manukanne"/>
    <language>en</language>
    <item>
      <title>A Python Implementation of the Unit of Work and Repository Design Pattern using SQLModel</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Mon, 22 May 2023 22:54:54 +0000</pubDate>
      <link>https://forem.com/manukanne/a-python-implementation-of-the-unit-of-work-and-repository-design-pattern-using-sqlmodel-3mb5</link>
      <guid>https://forem.com/manukanne/a-python-implementation-of-the-unit-of-work-and-repository-design-pattern-using-sqlmodel-3mb5</guid>
      <description>&lt;p&gt;In this blogpost I would like to introduce two design patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository pattern&lt;/li&gt;
&lt;li&gt;Unit of Work pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository pattern
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Repository pattern is a Domain-Driven Design pattern intended to keep persistence concerns outside of the system's domain model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means that the repository pattern represents our data layer and is a strict separation between domain and data model. A concrete repository gives access to an entity, an entity consists of one or more related tables:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfxs5meahq8b5dif6szv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfxs5meahq8b5dif6szv.png" alt="Example repository pattern implementation"&gt;&lt;/a&gt;&lt;br&gt;
Source: &lt;a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design#define-one-repository-per-aggregate" rel="noopener noreferrer"&gt;Design the infrastructure persistence layer - Define one repository per aggregate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A repository encapsulates all CRUD operations, in addition the repository also acts as an interface between domain and data model. This means that the domain and data model are only loosely coupled via well-defined interfaces.&lt;/p&gt;

&lt;p&gt;This approach offers several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❇️ Separation of domain and data model.&lt;/li&gt;
&lt;li&gt;❇️ Enabling of DDD and TDD. For each repository you can easily create so called fake repositories, which in turn can be used to create unit tests.&lt;/li&gt;
&lt;li&gt;❇️ Centralization of queries, all query functions are defined and maintained in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this pattern offers not only advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔴 Introduces another layer and increases the complexity.&lt;/li&gt;
&lt;li&gt;🔴 Leads, in dependence of in the implementation, to redudant code because eventually domain model and data model must be maintained twice and additionally a mapping logic between domain and data model and vice versa is required.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Unit of Work pattern
&lt;/h2&gt;

&lt;p&gt;This is a pattern that is commonly used with the repository pattern. To understand this pattern, we must first define the term "unit of work":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A unit of work refers to a single transaction that involves multiple insert, update, or delete operations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, all database operations should be handled in a single database transaction. This means that the repositories do not commit their respective transactions themselves, the database session of the repositories is managed by the unit of work instance, therefore the unit of work is also responsible for committing or rolling back the transaction.&lt;/p&gt;

&lt;p&gt;This is especially important when multiple repositories are involved: the unit of work instance ensures that either all or none of the database operations are committed, keeping our data consistent.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;A special challenge in the implementation is that the domain model must not be dependent on the data layer, otherwise the loose coupling is no longer given. For Java and C# there are various tutorials on how to implement this pattern, something that almost all these implementations have in common is that the domain and data model are developed separately, so there are separate domain model and separate data classes.&lt;/p&gt;

&lt;p&gt;Thus, the repository pattern is also responsible for the mapping between domain and data model. A consequence is that there are inevitably certain redudances and an additional mapping logic. In Python you would have basically the same problem but that is exactly where SQLModel comes to the rescue.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/fastapi" rel="noopener noreferrer"&gt;
        fastapi
      &lt;/a&gt; / &lt;a href="https://github.com/fastapi/sqlmodel" rel="noopener noreferrer"&gt;
        sqlmodel
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      SQL databases in Python, designed for simplicity, compatibility, and robustness.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;
  &lt;a href="https://sqlmodel.tiangolo.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/af233532c9930e308adc996aa83bb1dedcdda51a98bb9e252ca03e937767e919/68747470733a2f2f73716c6d6f64656c2e7469616e676f6c6f2e636f6d2f696d672f6c6f676f2d6d617267696e2f6c6f676f2d6d617267696e2d766563746f722e737667236f6e6c792d6c69676874" alt="SQLModel"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;em&gt;SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://github.com/fastapi/sqlmodel/actions?query=workflow%3ATest" rel="noopener noreferrer"&gt;
    &lt;img src="https://github.com/fastapi/sqlmodel/workflows/Test/badge.svg" alt="Test"&gt;
&lt;/a&gt;
&lt;a href="https://github.com/fastapi/sqlmodel/actions?query=workflow%3APublish" rel="noopener noreferrer"&gt;
    &lt;img src="https://github.com/fastapi/sqlmodel/workflows/Publish/badge.svg" alt="Publish"&gt;
&lt;/a&gt;
&lt;a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/sqlmodel" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/0e96f90d2f78e0786564981829f5001e75a0ea0d45055419528f2ddb51ae098b/68747470733a2f2f636f7665726167652d62616467652e73616d75656c636f6c76696e2e776f726b6572732e6465762f666173746170692f73716c6d6f64656c2e737667" alt="Coverage"&gt;
&lt;/a&gt;&lt;a href="https://pypi.org/project/sqlmodel" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/3003e9dcbfbbf08001f2f653400a95b6a915cd4245073538b67216f21fcd95ff/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f73716c6d6f64656c3f636f6c6f723d253233333444303538266c6162656c3d707970692532307061636b616765" alt="Package version"&gt;
&lt;/a&gt;
&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: &lt;a href="https://sqlmodel.tiangolo.com" rel="nofollow noopener noreferrer"&gt;https://sqlmodel.tiangolo.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source Code&lt;/strong&gt;: &lt;a href="https://github.com/fastapi/sqlmodel" rel="noopener noreferrer"&gt;https://github.com/fastapi/sqlmodel&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;SQLModel is a library for interacting with SQL databases from Python code, with Python objects. It is designed to be intuitive, easy to use, highly compatible, and robust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLModel&lt;/strong&gt; is based on Python type annotations, and powered by &lt;a href="https://pydantic-docs.helpmanual.io/" rel="nofollow noopener noreferrer"&gt;Pydantic&lt;/a&gt; and &lt;a href="https://sqlalchemy.org/" rel="nofollow noopener noreferrer"&gt;SQLAlchemy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The key features are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive to write&lt;/strong&gt;: Great editor support. Completion everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to use&lt;/strong&gt;: It has sensible defaults and does a lot of work underneath to simplify the code you write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatible&lt;/strong&gt;: It is designed to be compatible with &lt;strong&gt;FastAPI&lt;/strong&gt;, Pydantic, and SQLAlchemy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible&lt;/strong&gt;: You have all the power of SQLAlchemy and Pydantic underneath.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short&lt;/strong&gt;: Minimize code duplication. A single type annotation does a lot of work. No…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/fastapi/sqlmodel" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;So what can SQLModel do for us? SQLModel is from the same developer who developed FastAPI, so this library works very well with FastAPI, but can also be used for other projects.&lt;/p&gt;

&lt;p&gt;In FastAPI domain models are developed with Pydantic, Pydantic is responsible for data validation and serialization or deseralization of the data. FastAPI has no built-in ORM framework, a popular ORM framework is SQLAlchemy. What SQLModel does now is the combination of Pydantic and SQLAlchemy, so the models become domain and data model at the same time.&lt;/p&gt;

&lt;p&gt;Thanks to this particular feature, a major pain point can be eliminated, namely the need to maintain domain and data models, as well as the maintenance and development of a mapping logic between domain and data model.&lt;/p&gt;
&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;First, let's get a brief overview of the software we are going to create. For the tables I will follow the tutorials of SQLModel a little bit. Let's take a look at the class diagram first:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1f25ecckekovpv6t2nj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk1f25ecckekovpv6t2nj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This probably looks a bit overwhelming now, but stick with me, let's go through it step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;GenericRepository&lt;/em&gt;&lt;/strong&gt;: This is the abstract base class of a repository, in which all general repository functions are defined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;GenericSqlRepository&lt;/em&gt;&lt;/strong&gt;: Inherits from GenericRepository. This class wraps SQLModel and as the name suggests acts as a generic SQL repository. All concrete repositories will be inherited from this class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;HeroReposityBase and TeamRepositoryBase&lt;/em&gt;&lt;/strong&gt;: These classes are abstract classes that inherit from GenericRepository, where specific functionalities of the respective entities (hero and team) are defined. There are two approaches to the repository pattern: the generic and the "one repository per entity" approach. I personally prefer the second one, because you have the possibility to define specific functionalities, but this is a matter of preference or depends on the requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;HeroRepository and TeamRepository&lt;/em&gt;&lt;/strong&gt;: These repositories are concrete repositories, they inherit from GenericSqlRepository and from the respective entity base repositories (HeroReposityBase or TeamRepositoryBase), in which the entity specific functions are defined. The entity specific functions are implemented in these repositories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;UnitOfWorkBase&lt;/em&gt;&lt;/strong&gt;: Abstract context manager which defines the basic functions of the Unit of Work interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;UnitOfWork&lt;/em&gt;&lt;/strong&gt;: Concrete Unit of Work, inherits from the base class and wraps and manages the database session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Generally speaking, all of the above classes can be divided into two categories: abstract and concrete classes. For example, if you want to create fake classes for unit tests, you would have to create fake classes that inherit from all the "base" classes, i.e. from the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GenericRepository&lt;/li&gt;
&lt;li&gt;HeroReposityBase&lt;/li&gt;
&lt;li&gt;TeamRepositoryBase&lt;/li&gt;
&lt;li&gt;UnitOfWorkBase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All other classes are concrete classes and cannot be used for unit tests, unless you create integration tests in which you use e.g. an in-memory SQLite database.&lt;/p&gt;

&lt;p&gt;In this blogpost I will not cover the creation of unit tests, but as I said before only the abstract classes need to be derived. This concept is especially strong when working with a dependency injection system, so in unit tests the dependencies can be easily injected using DI, creating a loose coupling between domain and data layer.&lt;/p&gt;

&lt;p&gt;Let's write some code!&lt;/p&gt;

&lt;h3&gt;
  
  
  Defining the models
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see here I have defined my own base model, the settings chosen here are similar to what you would use in a FastAPI project. In the config you basically only set that the models can be imported and exported in a JSON compliant style.&lt;/p&gt;

&lt;p&gt;The concrete tables inherit from the base model. Contrary to the official documentation, I defined the columns via the property sa_column, passing an SQLALchemy column object as a parameter. This allows a more precise column definition, so the column name and the exact data type can be specified accurately. I personally prefer this approach, but of course you can also define the tables as described in the official SQLModel documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  ORM
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Engine and session factory
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This file contains the code needed to connect to a database, i.e. the creation of a SQLModel engine and session maker function. The latter returns a function which in turn returns a new database session whenever it is called.&lt;/p&gt;

&lt;h4&gt;
  
  
  Repositories
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Generic Repository
&lt;/h5&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As before, this is the base repository class which defines all basic functions (= CRUD).&lt;/p&gt;

&lt;h5&gt;
  
  
  SQL Repository
&lt;/h5&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This repository is a generic SQL repository. The constructor takes as arguments a database session and a SQLModel type. &lt;/p&gt;

&lt;p&gt;Here all methods are implemented and two new methods for the creation of the GET and LIST SQL statements. By introducing these two methods you could customize the SQL statements for GET and LIST in the derived repositories.&lt;/p&gt;

&lt;h5&gt;
  
  
  Base Entity Repositories
&lt;/h5&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;These repositories are the abstract base classes of the respective repositories. These classes are completely optional, but offer the advantage that entity-specific functions can be defined here, which should not be available for all repositories.&lt;/p&gt;

&lt;h5&gt;
  
  
  Entity repositories
&lt;/h5&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;These are now concrete repositories, here one could overload the functions of the general SQL repository, in addition the abstract methods of the respective base repositories are implemented here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Layer
&lt;/h3&gt;

&lt;p&gt;The Unit of Work functionalities are not directly part of the ORM framework, but is a service that connects everything together.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unit of Work
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The service unit of work is responsible for the handling of the session and thus guarantees that everything runs as a single unit of work.&lt;/p&gt;

&lt;p&gt;This service is a context manager that calls the session_maker aka session factory function each time in the &lt;strong&gt;enter&lt;/strong&gt; method and thus creates a new session each time. This session is passed on to the respective repositories, thereby ensuring that all operations run within one transaction.&lt;/p&gt;

&lt;p&gt;The rollback functions are always called at the end of the context manager. If the commit function was called before, the rollback function has no effect. If the commit function was not called before or an error occurred, the entire transaction is rolled back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's test it!
&lt;/h3&gt;

&lt;p&gt;Now that we have written all the necessary code, it is time to make some database calls:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Even if it requires a lot of boiler code, especially for larger projects these design patterns really pay off, because they achieve a strict separation of domain and data layer, and the layers are only loosely coupled with each other.&lt;/p&gt;

&lt;p&gt;As already mentioned, you could now derive the base classes and test the business logic without database operations. Alternatively, you can also run the unit tests with a SQLite in-memory database.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;If you've made it so far, thanks for reading! I hope I could bring you the two design patterns a bit newer and encourage you to use these patterns for your next project. Even though there is a lot of code involved in setting up this structure, I think these patterns will pay off especially for larger projects.&lt;/p&gt;

&lt;p&gt;All code is available at this repository, check it out!&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/manukanne" rel="noopener noreferrer"&gt;
        manukanne
      &lt;/a&gt; / &lt;a href="https://github.com/manukanne/sqlmodel-repository-pattern" rel="noopener noreferrer"&gt;
        sqlmodel-repository-pattern
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;SQLModel Repository pattern&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This repository includes a example implementation of the Unit of Work design and Repository design pattern.&lt;/p&gt;
&lt;p&gt;For more details please check out my &lt;a href="https://dev.to/manukanne/a-python-implementation-of-the-unit-of-work-and-repository-design-pattern-using-sqlmodel-3mb5" rel="nofollow"&gt;blog post&lt;/a&gt;!&lt;/p&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;---
title: Unit of Work + Repository pattern
---
classDiagram
     direction LR
    GenericRepository &amp;lt;|--GenericSqlRepository
    GenericRepository &amp;lt;|-- HeroReposityBase
    GenericRepository &amp;lt;|-- TeamRepositoryBase

    GenericSqlRepository &amp;lt;|-- TeamRepository
    TeamRepositoryBase &amp;lt;|-- TeamRepository
    GenericSqlRepository &amp;lt;|-- HeroRepository
    HeroReposityBase &amp;lt;|-- HeroRepository

    UnitOfWorkBase &amp;lt;|-- UnitOfWork
    HeroReposityBase *-- UnitOfWorkBase
    TeamRepositoryBase *-- UnitOfWorkBase

    HeroRepository *--UnitOfWork
    TeamRepository *--UnitOfWork

    class GenericRepository~SQLModel~{
        +get_by_id(int id) SQLModel
        +list(**filters) List~SQLModel~
        +add(T record) SQLModel
        +update(T recored) SQLModel
        +delete(id int)
    }

    class GenericSqlRepository~SQLModel~{
        -_construct_list_stmt(id)
        -_construct_list_stmt(**filters)
    }
    class HeroReposityBase{
        +get_by_name(str name) Hero
    }
    class HeroRepository{

    }
    class TeamRepositoryBase{
        +get_by_name(str name) Team
    }
    class TeamRepository{
    }
    class UnitOfWorkBase{
        teams: TeamRepositoryBase
        heroes: HeroReposityBase
        + __enter__()
        + __exit__()
        + commit()
        + rollback()
    }
    class UnitOfWork{
        teams: TeamRepository
        heroes: HeroRepository
    }

&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;
    &lt;span&gt;
  
    
    
    &lt;span class="sr-only"&gt;Loading&lt;/span&gt;
&lt;/span&gt;
  &lt;/span&gt;


&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Getting Started&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech-stack&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.10&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sqlmodel.tiangolo.com/" rel="nofollow noopener noreferrer"&gt;SQLModel&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.pydantic.dev/latest/" rel="nofollow noopener noreferrer"&gt;Pydantic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sqlalchemy.org/" rel="nofollow noopener noreferrer"&gt;SQLAlchemy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Setup&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;1. Clone the project:&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/manukanne/sqlmodel-repository-pattern" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Further references&lt;/p&gt;

&lt;h2&gt;
  
  
  Acknowledgments
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/" rel="noopener noreferrer"&gt;Architecture Patterns with Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application" rel="noopener noreferrer"&gt;Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sqlmodel.tiangolo.com/" rel="noopener noreferrer"&gt;SQLModel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>designpatterns</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Azure Functions for Python - Introduction to the new V2 programming model</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Wed, 21 Dec 2022 22:34:29 +0000</pubDate>
      <link>https://forem.com/manukanne/azure-functions-for-python-introduction-of-the-new-v2-programming-model-6h3</link>
      <guid>https://forem.com/manukanne/azure-functions-for-python-introduction-of-the-new-v2-programming-model-6h3</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently, Microsoft introduced a decorator based approach for the development of Python based functions. This concept is very similar to the approach that FastAPI follows. So what has changed?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ The V2 programming model is currently in public preview. Some things may still change, so the features described here should not be used in production yet. Also, not all trigger types are fully supported at this time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The V1 programming model
&lt;/h3&gt;

&lt;p&gt;With the v1 programming model, each trigger of a function consists of two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;function.json&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is a configuration file that defines, among other things, the trigger type of the function and how the data is bound.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;__init__.py&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contains the actual code of the function and must match the function.json (such as names of input or output variables defined in function.json).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For example, an HTTP Azure Function looks like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;function.json:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scriptFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"__init__.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bindings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"authLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"httpTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"req"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"methods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"post"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"out"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$return"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;__init__.py:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The V2 programming model
&lt;/h3&gt;

&lt;p&gt;As you could see in the V1 programming model, for each trigger two files are needed, one is a configuration of the trigger and the other is the actual code. This has changed with the V2 programming model, the configuration information can now be placed directly in the code via decoraters. &lt;/p&gt;

&lt;p&gt;For example, an HTTP Azure Function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt;

&lt;span class="nd"&gt;@app.function_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HttpTrigger1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;req&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;azure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The triggers can now be configured via decorates. The types of the attributes, both input and output, can be specified via type annotations.&lt;/p&gt;

&lt;p&gt;At the moment the following triggers and bingings are supported:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timer&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Queue Storage&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Service Bus topic&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Servuce Bus queue&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Comos DB&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Blob Storage&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Hub&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ As you can see here, not all triggers and binding are supported yet, but Microsoft will deliver them later. If your desired type is not listed yet, you have to stay with the programming model V1.&lt;br&gt;
For an up-to-date overview of all supported types, please check out this &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-triggers-python" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As you could already see the new programming model V2 leads to a simpler file structure and a more code based approach. Another cool feature introduced are the blueprints.&lt;/p&gt;

&lt;p&gt;In case you are familiar with FastAPI, blueprints may remind you of FastAPI router functionality. Blueprint allows to split the Azure Function into several modules and also to create interfaces that can be reused in other projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt; 

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; 

&lt;span class="n"&gt;bp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Blueprint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

&lt;span class="nd"&gt;@bp.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;default_template&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;default_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Python HTTP trigger function processed a request.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;req_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="k"&gt;pass&lt;/span&gt; 
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req_body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. This HTTP-triggered function &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;executed successfully.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This HTTP-triggered function executed successfully. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pass a name in the query string or in the request body for a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; personalized response.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt; 
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This blueprint then only needs to be imported and registered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;http_blueprint&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;bp&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FunctionApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_functions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A unique feature of Azure functions in combination with Python is the use of ASGI and WSGI compatible web frameworks, such as FastAPI or Flask. This is already possible with the programming model V1 and is also maintained here:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ASGI (FastAPI)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# function_app.py
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; 

&lt;span class="n"&gt;fast_app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

&lt;span class="nd"&gt;@fast_app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/return_http_no_body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;return_http_no_body&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;media_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/plain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsgiFunctionApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fast_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                           &lt;span class="n"&gt;http_auth_level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ANONYMOUS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;WSGI (Flask)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# function_app.py
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt; 

&lt;span class="n"&gt;flask_app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="nd"&gt;@flask_app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/return_http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;return_http&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;h1&amp;gt;Hello World™&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text/html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WsgiFunctionApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;flask_app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wsgi_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                           &lt;span class="n"&gt;http_auth_level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ANONYMOUS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These were my highlights of the programming model V2 for Python Azure Fuctions! Although this feature is still in preview, I find these changes incredibly exciting as they allow us to develop Azure Functions with a more code based approach, similar to FastAPI.&lt;/p&gt;

&lt;p&gt;However, keep in mind that these are preview features at this time and may change. Also, not all triggers and binding types are &lt;br&gt;
supported currently, but these will surely follow shortly!&lt;/p&gt;

&lt;p&gt;Let me know your thoughts on this and thanks for reading!&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-python?tabs=wsgi%2Capplication-level&amp;amp;pivots=python-mode-decorators" rel="noopener noreferrer"&gt;Azure Functions Python developer guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-triggers-python" rel="noopener noreferrer"&gt;Python V2 model Azure Functions triggers and bindings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>learning</category>
    </item>
    <item>
      <title>Data Structures: Arrays and Lists in Comparison</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Tue, 20 Dec 2022 01:22:14 +0000</pubDate>
      <link>https://forem.com/manukanne/data-structures-arrays-and-lists-in-comparison-518p</link>
      <guid>https://forem.com/manukanne/data-structures-arrays-and-lists-in-comparison-518p</guid>
      <description>&lt;p&gt;Usually, when you start your programming journey, the first data types you come up against are arrays and lists. Arrays are a fundamental data type, many more complex data types are built on top of arrays. Let's have a look at arrays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F89idgi161uuj3442a2fh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F89idgi161uuj3442a2fh.png" alt="Array indices" width="512" height="201"&gt;&lt;/a&gt;&lt;br&gt;
We have just created an array with a length of 4. Arrays use the contiguous memory allocation technique for memory allocation. This means that all the fields must be continuous next to each other:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2vk9c7fxrimw93o08r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff2vk9c7fxrimw93o08r8.png" alt="Array memory allocation" width="441" height="361"&gt;&lt;/a&gt;&lt;br&gt;
There were not four consecutive memory blocks free in the first row, so the required memory for the array was allocated in the second row.&lt;/p&gt;

&lt;p&gt;So far so good. Now let's imagine we want to resize our array because we want to store e.g. 6 values. What we would have to do is to create a new array with a length of 6 and copy the values of the previous array into the new array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;[]{&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;biggerArr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CopyTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;biggerArr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg3o51mg5u6zn6615t0k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffg3o51mg5u6zn6615t0k.png" alt="Copy array" width="681" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we now think of lists, lists have a key characteristic: you don't have to specify a fixed length in advance, lists can dynamically allocate more memory. For lists, however, you can specify a capacity value; if no value is specified, a default value is used. This default value varies depending on the programming language. Lists also use arrays in the background, so the given capacity size represents the size of the initial array. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;+=&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Added &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to list. Current list capacity is &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Capacity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Added 10 to list. Current list capacity is 2
Added 20 to list. Current list capacity is 2
Added 30 to list. Current list capacity is 4
Added 40 to list. Current list capacity is 4
Added 50 to list. Current list capacity is 8
Added 60 to list. Current list capacity is 8
Added 70 to list. Current list capacity is 8
Added 80 to list. Current list capacity is 8
Added 90 to list. Current list capacity is 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The initial capacity is 2. As soon as this was exceeded, the capacity doubled, i.e. it was 4. As soon as the capacity of 4 was exceeded, it doubled again, and so on.&lt;/p&gt;

&lt;p&gt;When we resized our array in our previous example, we basically did something similar than the list. With one exception. If we remember, the occupied memory of an array must always be contiguous. But this is not true for lists, here the allocated memory is not contiguous and may looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn49p0yoseta806159w3q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn49p0yoseta806159w3q.png" alt="Memory allocation of a list" width="681" height="441"&gt;&lt;/a&gt;&lt;br&gt;
The list consists of many small, not directly contiguous memory blocks. What is immediately noticeable is that this allows the list to make better use of the available memory. If, as in the chosen example, we need to allocate memory for an array with a length of 16, a memory block with an appropriate length must first be found.&lt;/p&gt;

&lt;p&gt;But don't get me wrong, this doesn't mean that arrays are inefficient data structures, quite the opposite! Arrays are one of the most efficient data structures ever, especially when we access values via indexes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2dnn2d3fj8vku7y1lxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2dnn2d3fj8vku7y1lxk.png" alt="Memory allocation - array vs lists" width="561" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I know this looks a little bit messy, but stay with me! The two diagrams show how our memory could be distributed. Our program or our process probably does not have one large continuous block, but many small blocks, in between other processes or programs also occupy memory. On the left side we see in blue our array and on the right side in purple our list.&lt;/p&gt;

&lt;p&gt;If we now imagine we want to access any element of our array. Because arrays always allocate a continuous block of memory, we always know exactly where an array begins and ends. This makes it extremely easy to access elements using indexes.&lt;br&gt;
This is different for lists. Elements of a list are also accessed via indexes, but since the elements are not on a continuous memory block, such accesses can be very costly. Of course, this depends primarily on the size of the list, but with large amounts of data, the array will always win.&lt;/p&gt;

&lt;p&gt;Does this mean that arrays are better than lists? As always, it depends. If we want to increase our array size, this is an extremely expensive task. As shown before, we need to create a new array with the desired length and copy all the values of the original array. &lt;br&gt;
Lists, on the other hand, simply allocate new memory dynamically. Even if elements are removed, the list can free memory dynamically. So for many add and delete operations, the list clearly has the upper hand. In addition, an array always occupies a fixed amount of memory, regardless of whether all fields are assigned values or not.&lt;/p&gt;

&lt;p&gt;Summary:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;&lt;/th&gt;
    &lt;th&gt;Array&lt;/th&gt;
    &lt;th&gt;List&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Length&lt;/td&gt;
    &lt;td&gt;Arrays always have a fixed length. The length of an array cannot be changed, a new array must always be created with a copy of the previous values.&lt;/td&gt;
    &lt;td&gt;Lists can be resized dynamically.&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Memory consumption&lt;/td&gt;
    &lt;td&gt;Arrays have a fixed length and the memory is contiguous. Generally speaking, arrays are more memory efficient than lists, unless the array is oversized.&lt;/td&gt;
    &lt;td&gt;Lists have a non-contiguous memory space, therefore the internal implementation of the list is more complex and needs additional structures that consume more memory.&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Usage&lt;/td&gt;
    &lt;td&gt;Arrays are pointed if the number of elements is known. In addition, due to the contiguous memory, elements can be quickly accessed via indexes.&lt;/td&gt;
    &lt;td&gt;Because lists can resize themselves automatically, they are particularly suitable for frequent add and remove operations and can thus also achieve a better memory performance than arrays under certain circumstances.&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Finally, I would like to emphasize that there is no clear winner here, it simply depends on the use-case. In most cases the list is the better choice, most of the time you don't know how big or small the amount of data is and lists can allocate the needed size dynamically. &lt;/p&gt;

&lt;p&gt;I hope I could bring you a little bit closer to how arrays and lists work in the background. I tried to stay as general as possible without going into a specific programming language, in essence this should work similarly for all programming languages.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed my blogpost, thanks for reading! If you have any suggestions or comments, let me know!&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Implement a Batch API using FastAPI</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Sat, 19 Nov 2022 13:52:24 +0000</pubDate>
      <link>https://forem.com/manukanne/implement-a-batch-route-using-fastapi-444d</link>
      <guid>https://forem.com/manukanne/implement-a-batch-route-using-fastapi-444d</guid>
      <description>&lt;p&gt;In this blogpost I would like to present you a possible implementation for a batch route using FastAPI. FastAPI is a great framework for creating REST API's, unfortunately there is currently no native support for batching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why batching?
&lt;/h2&gt;

&lt;p&gt;Batching is the process of combining multiple API requests into a single request with a single response. Without batching, the whole thing looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid.live/edit#pako:eNrNkMEKwjAQRH8l7Ln-QA4F0Ys3sddc1mbUYrOtm0SQ0n83tfQfvO0MbwZ2JmoHD7IU8cqQFseO78rBieGcBsnhCi3i0HeQZHZ1bRroG2rN_nwylyUVUwFW9wes7AbEcZCIv6kwVFGABu58-XpaHEfpgQBHtpye9enIyVy4ZYHmIy3ZpBkV5dFz2hYie-M-Yv4C4eBsfQ" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNrNkMEKwjAQRH8l7Ln-QA4F0Ys3sddc1mbUYrOtm0SQ0n83tfQfvO0MbwZ2JmoHD7IU8cqQFseO78rBieGcBsnhCi3i0HeQZHZ1bRroG2rN_nwylyUVUwFW9wes7AbEcZCIv6kwVFGABu58-XpaHEfpgQBHtpye9enIyVy4ZYHmIy3ZpBkV5dFz2hYie-M-Yv4C4eBsfQ%3Ftype%3Dpng" alt="Without batch requests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each request between client and server has a certain network latency, so the processing of several consecutive requests can take some time.&lt;/p&gt;

&lt;p&gt;With a batch request, the roundtrip between client and server and thus the number of requests can be reduced, which in turn rapidly improves performance:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mermaid.live/edit#pako:eNq9kEEOwjAMBL8S-QwfyKEH4AX0motJFlrRuMVJkFDVv5OqQogPcLN3x9KuZ_JjAFlKeBSIx6nnm3J0YrjkUUq8QOtyHHpINvumMS30CbXmwNl35rzepVyRTf9B_mluCb-x0jRKQmUM7ShCI_eh9pxXxVHuEOHI1jGw3h05WSq3dm5f4slmLdhRmQLnz0_IXnlIWN6xGmo5" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmermaid.ink%2Fimg%2Fpako%3AeNq9kEEOwjAMBL8S-QwfyKEH4AX0motJFlrRuMVJkFDVv5OqQogPcLN3x9KuZ_JjAFlKeBSIx6nnm3J0YrjkUUq8QOtyHHpINvumMS30CbXmwNl35rzepVyRTf9B_mluCb-x0jRKQmUM7ShCI_eh9pxXxVHuEOHI1jGw3h05WSq3dm5f4slmLdhRmQLnz0_IXnlIWN6xGmo5%3Ftype%3Dpng" alt="With batch requests"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical consideration of the batch route
&lt;/h2&gt;

&lt;p&gt;In the course of my research, I looked at the batch routes of other major API's, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/graph/json-batching" rel="noopener noreferrer"&gt;Microsoft Graph API Batch Route&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/make-batch-requests-with-the-rest-apis" rel="noopener noreferrer"&gt;Microsoft Sharepoint API Batch Route&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/storage/docs/batch" rel="noopener noreferrer"&gt;Google Cloud Storage API Batch Route&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on the API's listed above, there are two different ways to submit batch requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submit batch request with MIME type multipart/mixed

&lt;ul&gt;
&lt;li&gt;The advantage of this approach is that requests can be sent with different MIME types (e.g. application/json, application/http, application/octet-stream etc.).&lt;/li&gt;
&lt;li&gt;The body of the request is divided into parts that are separated from each other by a boundary string that is specified in the header of the request.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Submit batch request with MIME type application/json

&lt;ul&gt;
&lt;li&gt;The batch request is submitted in JSON format. This limits the API to the MIME type application/json.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I personally prefer the JSON batch approach, assembling the batch request is slightly easier with this approach. Of course this approach is limited to the MIME type application/json only, but since most FastAPI routes implement exactly this MIME type this is acceptable for me. The choice therefore varies simply on the technical requirements.&lt;/p&gt;

&lt;p&gt;Our batch route is therefore inspired by the Microsoft Graph API, the batch request will have the following structure:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;

&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/batch&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products?skip=0&amp;amp;limit=1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products/1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Test Product"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Mandatory&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;id&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;A correlation value to associate individual responses with requests. This value allows the server to process requests in the batch in the most efficient order.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;url&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;The relative resource URL the individual request would typically be sent to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;method&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;The HTTP method (e.g. GET, POST etc.).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;headers&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;A JSON object with the key/value pair for the headers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;body&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;JSON body.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The next step is to consider how the individual requests should be processed on the server side. Behind each FastAPI route there is a corresponding Python function that can be called directly. At first this sounds like a good idea, but then FastAPI is no longer able to determine the dependencies via depency injection, so we would have to do this manually. &lt;/p&gt;

&lt;p&gt;Determining the dependencies manually could be difficult and probably often leads to unexpected behavior of the API route. So I did some research and came across this repository: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dtkav" rel="noopener noreferrer"&gt;
        dtkav
      &lt;/a&gt; / &lt;a href="https://github.com/dtkav/flask-batch" rel="noopener noreferrer"&gt;
        flask-batch
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Handle many API calls from a single HTTP request
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="rst"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Flask-Batch&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://travis-ci.org/dtkav/flask-batch/" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Travis CI build status" src="https://camo.githubusercontent.com/487af9ae8fcee1795017bc5709615acb9c5cb3e55dca9d782a3f4520d6337869/68747470733a2f2f6170692e7472617669732d63692e6f72672f64746b61762f666c61736b2d62617463682e7376673f6272616e63683d6d6173746572"&gt;&lt;/a&gt; &lt;a href="https://github.com/dtkav/flask-batch/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img alt="GitHub license" src="https://camo.githubusercontent.com/d75937c357667a8f7cdfe59eab624255efbd42f81dbd9501640ca4ee910eae03/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f64746b61762f666c61736b2d62617463682e737667"&gt;
&lt;/a&gt; &lt;a href="https://pypi.python.org/pypi/flask-batch" rel="nofollow noopener noreferrer"&gt;&lt;img alt="Latest Version" src="https://camo.githubusercontent.com/f127aef461eb4c356ff5cb00d9a88ff77f6dc0bdc22e9dcfd251830169e1fc8b/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f666c61736b2d62617463682e737667"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Batch multiple requests at the http layer.&lt;/em&gt; Flask-Batch is inpsired by
&lt;a href="https://cloud.google.com/storage/docs/json_api/v1/how-tos/batch" rel="nofollow noopener noreferrer"&gt;how google cloud storage does
batching&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It adds a &lt;code&gt;/batch&lt;/code&gt; route to your API which can execute batched HTTP
requests against your API server side. The client wraps several requests
in a single request using the &lt;code&gt;multipart/mixed&lt;/code&gt; content type.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install Flask-Batch

&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; to include the dependencies for the batching client&lt;/span&gt;
pip install Flask-Batch[client]&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Server&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;flask&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-v"&gt;Flask&lt;/span&gt;
&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;flask_batch&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;add_batch_route&lt;/span&gt;

&lt;span class="pl-s1"&gt;app&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-v"&gt;Flask&lt;/span&gt;(&lt;span class="pl-s1"&gt;__name__&lt;/span&gt;)
&lt;span class="pl-en"&gt;add_batch_route&lt;/span&gt;(&lt;span class="pl-s1"&gt;app&lt;/span&gt;)

&lt;span class="pl-c"&gt;# that's it!&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Client&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The client wraps a requests session.&lt;/p&gt;
&lt;div class="highlight highlight-source-python notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;flask_batch&lt;/span&gt;.&lt;span class="pl-s1"&gt;client&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-v"&gt;Batching&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;json&lt;/span&gt;
&lt;span class="pl-s1"&gt;alice_data&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;bob_data&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {&lt;span class="pl-s"&gt;"example"&lt;/span&gt;: &lt;span class="pl-s"&gt;"json"&lt;/span&gt;}

&lt;span class="pl-k"&gt;with&lt;/span&gt; &lt;span class="pl-v"&gt;Batching&lt;/span&gt;(&lt;span class="pl-s"&gt;"http://localhost:5000/batch"&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;alice&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-en"&gt;patch&lt;/span&gt;(&lt;span class="pl-s"&gt;"/people/alice/"&lt;/span&gt;, &lt;span class="pl-s1"&gt;json&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;alice_data&lt;/span&gt;)
    &lt;span class="pl-s1"&gt;bob&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;s&lt;/span&gt;.&lt;span class="pl-en"&gt;patch&lt;/span&gt;(&lt;span class="pl-s"&gt;"/people/bob/"&lt;/span&gt;, &lt;span class="pl-s1"&gt;json&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;bob_data&lt;/span&gt;)

&lt;span class="pl-s1"&gt;alice&lt;/span&gt;         &lt;span class="pl-c"&gt;#&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/dtkav/flask-batch" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Flask-Batch performs batching on the HTTP layer. This means that on the server side a HTTP client executes all batch requests. The network latency is much lower on the server side which implies that the requests can be processed faster on the server side. Additionally, since the requests are processed on the HTTP layer, FastAPI is also able to resolve the dependencies via dependicy injection. Therefore I also decided to do batching on HTTP level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Defining the batch models
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  HTTPVerbs
&lt;/h4&gt;

&lt;p&gt;This enum defines the allowed HTTP methods.&lt;/p&gt;

&lt;h4&gt;
  
  
  BatchRequest
&lt;/h4&gt;

&lt;p&gt;This model represents a single API request. This model also ensures that the referenced endpoint meets our requirements, in this case that no absolute URL is given and that the route starts with a leading slash. Especially the check that it is not an absolute URL is extremely important to prevent potential improper usage of our batch route.&lt;/p&gt;

&lt;h4&gt;
  
  
  BatchResponse
&lt;/h4&gt;

&lt;p&gt;This model represents the result of the corresponding request. Here also the ID of the request is returned so that the client can map request and response (theoretically the order of processing could vary). Besides the ID, the HTTP status code, the headers and the JSON body are also returned.&lt;/p&gt;

&lt;h4&gt;
  
  
  BatchIn
&lt;/h4&gt;

&lt;p&gt;This is the container that includes all our batch requests. Here it is also checked if all ID's are unique and the allowed maximum amount of requests has not been exceeded.&lt;/p&gt;

&lt;h4&gt;
  
  
  BatchOut
&lt;/h4&gt;

&lt;p&gt;This is the container that holds all the responses, this model is the one that is passed back to the caller.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implement the batch route
&lt;/h3&gt;

&lt;p&gt;The batch requests are processed using the Python package &lt;a href="https://docs.aiohttp.org/en/stable/index.html" rel="noopener noreferrer"&gt;aiohttp&lt;/a&gt;. This allows the requests to be processed in an asynchronous manner. One blog post that helped me a lot with the implementation is the post &lt;a href="https://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html" rel="noopener noreferrer"&gt;Making 1 million requests with python-aiohttp&lt;/a&gt; which I would definitely like to recommend to you!&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the next step we implement the actual batch route, here we just have to plug everything together:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The repository, which contains all the code including a small test API, can be found here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/manukanne" rel="noopener noreferrer"&gt;
        manukanne
      &lt;/a&gt; / &lt;a href="https://github.com/manukanne/fastapi-batch-requests-demo" rel="noopener noreferrer"&gt;
        fastapi-batch-requests-demo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;FastAPI Batch Tutorial&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This repository contains a possible implementation of a batch route using FastAPI
For more details, please check out my blog post on &lt;a href="https://dev.to/manukanne/implement-a-batch-route-using-fastapi-444d" rel="nofollow"&gt;dev.to&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Json based batching - The data is exchanged using the MIME type application/json, this approach is
inspired by the &lt;a href="https://learn.microsoft.com/en-us/graph/json-batching" rel="nofollow noopener noreferrer"&gt;Microsoft Graph Batch API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Batching takes place on the HTTP layer. This approach was chosen to ensure consistent behaviour.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Why batching&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Batching is the process of combining multiple API requests into a single request with a single response.
Without batching, the whole thing looks like this:&lt;/p&gt;

  &lt;div class="js-render-enrichment-target"&gt;
    &lt;div class="render-plaintext-hidden"&gt;
      &lt;pre&gt;sequenceDiagram
 autonumber
 Client -&amp;gt;&amp;gt; Server: API Request
 Server -&amp;gt;&amp;gt; Client: API Response
 Client -&amp;gt;&amp;gt; Server: API Request
 Server -&amp;gt;&amp;gt; Client: API Response
 Client -&amp;gt;&amp;gt; Server: API Request
 Server -&amp;gt;&amp;gt; Client: API Response
&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;span class="js-render-enrichment-loader d-flex flex-justify-center flex-items-center width-full"&gt;
    &lt;span&gt;
  
    
    
    &lt;span class="sr-only"&gt;Loading&lt;/span&gt;
&lt;/span&gt;
  &lt;/span&gt;


&lt;p&gt;Each request between client and server has a certain network latency, so the processing of
several consecutive requests can take some time.&lt;/p&gt;
&lt;p&gt;With a…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/manukanne/fastapi-batch-requests-demo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Bathing is an important component to combine many requests to a single API call and thus increase the performance rapidly. &lt;br&gt;
I hope you enjoyed my blog, thanks for reading! If you have any recommendations on how to improve my implementation, please let me know in the comments section.&lt;/p&gt;

</description>
      <category>python</category>
      <category>architecture</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Infrastructure as Code - Deploy an Azure Function using Bicep</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Mon, 25 Apr 2022 17:58:52 +0000</pubDate>
      <link>https://forem.com/manukanne/azure-infrastructure-as-code-deploy-an-azure-function-using-bicep-1i04</link>
      <guid>https://forem.com/manukanne/azure-infrastructure-as-code-deploy-an-azure-function-using-bicep-1i04</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this guide, we will look at the topic &lt;em&gt;Infrastructure as Code&lt;/em&gt; using the example of an Azure Function. But what is Infrastructure as Code? Based from the official Microsoft documentation, Infrastructure as Code can be described as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Infrastructure as Code (IaC) is the management of infrastructure (networks, virtual machines, load balancers, and connection topology) in a descriptive model, using the same versioning as DevOps team uses for source code. Like the principle that the same source code generates the same binary, an IaC model generates the same environment every time it is applied. IaC is a key DevOps practice and is used in conjunction with continuous delivery.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A key property of IaC is the so-called &lt;em&gt;Idempotence&lt;/em&gt;, which means that the deployment command always brings the target system into the desired state, regardless of the initial state. This can be achieved either by configuring the target system or by creating a fresh environment.&lt;/p&gt;

&lt;p&gt;In simpler terms, IaC ensures that we always have the desired configuration of our target system. In classic on-prem scenarios, the target systems are unique, e.g. staging and production systems may differ. These differences can cause the application to work on the staging system but then fail on the production system (e.g. missing permissions, network access, etc.). IaC tackles this issues and helps to reduce such risks. Additionally, since the required infrastructure is now available as code, it can be easily versioned via Git.&lt;/p&gt;

&lt;p&gt;For IaC various tools are around:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview" rel="noopener noreferrer"&gt;Azure Resource Templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener noreferrer"&gt;Azure Bicep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/" rel="noopener noreferrer"&gt;Pulumi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.chef.io/products/chef-infra" rel="noopener noreferrer"&gt;Chef&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://puppet.com/" rel="noopener noreferrer"&gt;Puppet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;others...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The built-in tools for Azure are ARM and Bicep Templates, the other tools listed are third party tools for which additional costs may apply.&lt;br&gt;
In this guide we will cover only ARM and (mainly) Bicep. ARM and Bicep offer the advantage that they are developed directly by Microsoft and therefore always have access to the latest features. The only downside is that these technologies are not suitable for multicloud scenarios, as they are developed exclusively for the Microsoft Azure Cloud. &lt;br&gt;
Also, another plus point for ARM and Bicep, both are free and fully supported by Microsoft 😉.&lt;/p&gt;
&lt;h3&gt;
  
  
  ARM vs. Bicep
&lt;/h3&gt;

&lt;p&gt;ARM and Bicep both offer basically the same functionalities, but Bicep is a newer technology compared to ARM, so it can happen that some ARM features are not yet available in Bicep (for example like &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/user-defined-functions" rel="noopener noreferrer"&gt;User-defined ARM Functions&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;ARM templates are JSON files, all resources are represented as JSON. Bicep on the other hand is a declarative language, comparable to Terraform. Let's have a look:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example ARM Template&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"contentVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"defaultValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[resourceGroup().location]"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"storageAccountName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"defaultValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[format('toylaunch{0}', uniqueString(resourceGroup().id))]"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Microsoft.Storage/storageAccounts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"apiVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2021-06-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[parameters('storageAccountName')]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[parameters('location')]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Standard_LRS"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"StorageV2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"accessTier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hot"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Example Bicep Template&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I think it's obvious that the Bicep template is significantly shorter and even if you've never worked with either technology, it's much easier to see what's going on inside the Bicep template than in the ARM template.&lt;/p&gt;

&lt;p&gt;In my opinion, Bicep offers the following advantages over ARM templates:&lt;br&gt;
👑 Less code&lt;br&gt;
👑 Much easier to read&lt;br&gt;
👑 Fully integrated into VS Code with awesome intellisense capabilities&lt;/p&gt;

&lt;p&gt;Even if you need ARM templates, you can compile Bicep into ARM templates. This actually happens in the background when you deploy a Bicep template to Azure. During the deployment the Bicep template is compiled into an ARM template and then the ARM template is submitted to Azure.&lt;/p&gt;

&lt;p&gt;It is also possible to decompile an ARM template and thus convert an ARM to a Bicep template.&lt;/p&gt;

&lt;p&gt;Personally, I think if you don't have a strong reason to use ARM templates, you should definitely use Bicep, as the syntax is much simpler and more readable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Perquisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Azure Account with an active subscription. In case you do not have an Azure Account, go ahead and create one for free &lt;a href="https://azure.microsoft.com/en-us/free/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" rel="noopener noreferrer"&gt;Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install" rel="noopener noreferrer"&gt;Bicep Tools&lt;/a&gt; for Azure CLI and VS Code &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ It is absolutely possible to create the Bicep templates with the editor of your choice, however, I strongly recommend you to try the VS Code Extension for Bicep as it greatly simplifies the template development. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Azure Function Resources Overview
&lt;/h3&gt;

&lt;p&gt;Before we actually getting started, let's take a look at what resources we typically need for an Azure Function:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmbrgxi5nf707mysw02i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmbrgxi5nf707mysw02i.png" alt="Azure Function Resources Overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function App&lt;/strong&gt;&lt;br&gt;
This is the actual "Function App" service, where the code is running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App Service Plan&lt;/strong&gt;&lt;br&gt;
The App Service Plan is comparable to a web server and describes how the Function App is hosted. The App Plan also specifies how the Function App scales, the resources available per instance, and which "advanced" features can be used, such as Azure Virtual Network connectivity. In addition, different prices apply depending on the choice of the hosting plan. The following plans are available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consumption Plan (= serverless)&lt;/li&gt;
&lt;li&gt;Premium Plan&lt;/li&gt;
&lt;li&gt;Dedicated hosting plan &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, please checkout the official documentation on &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale#overview-of-plans" rel="noopener noreferrer"&gt;Azure Functions hosting options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage Account&lt;/strong&gt;&lt;br&gt;
When using the Consumption/Premium hosting plan, the function code and binding configuration files are stored in Azure Files in the main storage account. In addition, certain platform features may use the storage account for internal operations, such as &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview" rel="noopener noreferrer"&gt;Azure Durable Functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fore more information, please checkout the official documentation on &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/storage-considerations" rel="noopener noreferrer"&gt;Azure Function Storage Considerations&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Application Insights (optional)&lt;/strong&gt;&lt;br&gt;
Application Insights is the preferred monitoring service of Azure Functions and offers built-in logging functionalities. Application Insights collects log, performance, and error data. By automatically detecting performance anomalies and featuring powerful analytics tools, you can more easily diagnose issues and better understand how your functions are used. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ Application insights is an optional service that is billed separately. However, the cost are very low and it is highly recommended to use it with your Function App.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more information, please checkout the official documentation on &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-monitoring" rel="noopener noreferrer"&gt;Monitoring Azure Functions&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;Azure Application Insights&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Vault (optional)&lt;/strong&gt;&lt;br&gt;
Azure Key Vault is a cloud service for securely storing and accessing secrets. A secret is anything to which access should be strictly controlled, such as API keys, passwords, certificates, or cryptographic keys.&lt;/p&gt;

&lt;p&gt;Azure Key Vault Secrets can only be accessed via a secured and authenticated connection. In the context of the Azure Function, a system or user assigned identity must be created with which the Azure Function authenticates itself to the Key Vault service. The permissions must then be set up on the Key Vault in form of an access policy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ Azure Key Vault is an optional service and is primarily used for secure storage and retrieval of sensitive data. Storing sensitive data directly in the function is not recommended, as this data is stored in plain text, meaning that anyone who has access to the storage account can read this information. In addition to secrets, certificates and keys can also be stored in the Key Vault, and the Key Vault also offers various other functionality such as the encryption of data via public and private key. This service is also charged separately. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To learn more about &lt;a href="https://docs.microsoft.com/en-us/azure/key-vault/general/overview" rel="noopener noreferrer"&gt;Azure Key Vault&lt;/a&gt; or on how to &lt;a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references" rel="noopener noreferrer"&gt;Integrate Azure Key Vault into your Azure Function&lt;/a&gt;, please checkout the official documentation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Templates
&lt;/h3&gt;

&lt;p&gt;Now that we know what resources we need for our function, we can proceed with the development of the templates.&lt;/p&gt;
&lt;h4&gt;
  
  
  Storage Account
&lt;/h4&gt;

&lt;p&gt;This template creates the Storage Account, for later use the connection string is constructed and exported. The connection string is needed later in order to connect the Function App to the storage account.&lt;/p&gt;

&lt;p&gt;As briefly mentioned before, certain function features, such as Durable Functions, require certain Storage Services. If further storage services are required, they can be added to this template.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Application Insights
&lt;/h4&gt;

&lt;p&gt;Creates the Application Insights Resource for monitoring the Function App. To connect the Application Insights instance to the Function App, the Instrumentation Key must be exported for later assignment.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  App Service Plan
&lt;/h4&gt;

&lt;p&gt;Deploys the App Service Plan of the Function, here the plan id is exported for later usage.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;⚠️ The operating system varies depending on the language, please make sure to use the correct OS based on the chosen programming language, for more details please checkout the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-scale#operating-systemruntime" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Function App (without settings)
&lt;/h4&gt;

&lt;p&gt;Deploys the function app without settings, here also the previously exported plan id is passed into the template (the plan id specifies the selected hostion option of the Azure Function). &lt;br&gt;
Also a Managed Identity is assigned, as discussed before this is needed for the authentication against the Key Vault. The identity information, such as principal id and tenant id, as well as the name of the Function App are exported for later use.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Key Vault
&lt;/h4&gt;

&lt;p&gt;Creates the Key Vault. The previously configured managed identity is passed to the template and the necessary permissions for this managed identity are then set up using an access policy. In addition, any required secrets are created here and then exported for later referencing.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Function App Settings
&lt;/h4&gt;

&lt;p&gt;Creates the Function App Settings. Here various settings of the Function App are set, such as the Storage Account, the Application Insights instance, Function App runtime and any other custom parameters including secrets.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Main
&lt;/h4&gt;

&lt;p&gt;In order to create the function this template must be deployed. This template glues everything together and deploys all previously created templates in the correct order. The dependencies of the resources are also defined here, e.g. the function app should only be deployed if the deployment of the storage account, the application insights instance and the app service plan was successful. &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;For creating the function, a resource group is required in advance. If the desired resource group is already present, this step can be skipped.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az group create &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;name&amp;gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &amp;lt;location&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;For the deployment various parameters have to be specified including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Location&lt;/li&gt;
&lt;li&gt;Storage Account name&lt;/li&gt;
&lt;li&gt;Storage Account SKU&lt;/li&gt;
&lt;li&gt;Application Insights name&lt;/li&gt;
&lt;li&gt;App Service Plan name&lt;/li&gt;
&lt;li&gt;Function App operating system&lt;/li&gt;
&lt;li&gt;Function App name&lt;/li&gt;
&lt;li&gt;Function App runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have two options for specifying the parameters:&lt;br&gt;
&lt;em&gt;Inline parameters&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az deployment group create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; testgroup &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; &amp;lt;path-to-bicep&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameters&lt;/span&gt; &lt;span class="nv"&gt;exampleString&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'inline string'&lt;/span&gt; &lt;span class="nv"&gt;exampleArray&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'("value1", "value2")'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Parameter file&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az deployment group create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; ExampleDeployment &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; ExampleGroup &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; storage.bicep &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--parameters&lt;/span&gt; @storage.parameters.json


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Since we need have to specify a few parameters I suggest that we go with the parameter file variant. A parameter also offers the following advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is part of the repository and can therefore be versioned in Git&lt;/li&gt;
&lt;li&gt;A separate configuration can be created for each environment (e.g. staging, production, etc.)&lt;/li&gt;
&lt;li&gt;Facilitates deployment via CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The parameter looks like this, please just adjust the parameters as needed:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ For Azure there are recommendations from Microsoft on how resources should be named, for more details please checkout &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations" rel="noopener noreferrer"&gt;Recommended abbreviations for Azure resource types&lt;/a&gt;. Of course, these are only recommendations, resources can be named in any way you like.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To deploy the Azure Function we can use the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az deployment group create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &amp;lt;deployment-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &amp;lt;resource-group-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template-file&lt;/span&gt; bicep&lt;span class="se"&gt;\m&lt;/span&gt;ain.bicep
  &lt;span class="nt"&gt;--parameters&lt;/span&gt; @&amp;lt;path-to-parameters&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ For some names there are certain limitations, e.g. special characters, character lengths, etc. For example, the name of a storage account must be between 3 and 24 characters, should not contain any special characters and the name must be globally unique. If an error occurs during deployment, please read the error message carefully and adjust the names if necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it! Deployment takes a few seconds and then the Azure Function is ready to go.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Infrastructure as Code is an extremely powerful tool and an important building block that paves the way for further DevOps steps, such as the automated creation and configuration of environments via CI/CD mechanics.&lt;br&gt;
On top of that, Microsoft offers with Bicep and VS Code two excellent tools with which the creation of templates is a breeze.&lt;/p&gt;

&lt;p&gt;Even if we have only looked at the tip of the iceberg, I hope I could awaken your interest and that you liked my blog post.&lt;/p&gt;

&lt;p&gt;Thanks for reading, if you have any questions feel free to leave a comment 😃 &lt;/p&gt;

&lt;p&gt;Here you can find the repository with the full source code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/manukanne" rel="noopener noreferrer"&gt;
        manukanne
      &lt;/a&gt; / &lt;a href="https://github.com/manukanne/tutorial-az-func-iac" rel="noopener noreferrer"&gt;
        tutorial-az-func-iac
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Deploy an Azure Function using Bicep&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;This project illustrates how an Azure Function can be deployed as IaC via Bicep.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;The project provides the following Bicep templates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function App (without settings)&lt;/li&gt;
&lt;li&gt;App Service Plan&lt;/li&gt;
&lt;li&gt;Storage Account&lt;/li&gt;
&lt;li&gt;Application Insights&lt;/li&gt;
&lt;li&gt;Key Vault&lt;/li&gt;
&lt;li&gt;Function App Settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The individual resources can be found under the &lt;a href="https://github.com/manukanne/tutorial-az-func-iacbicep/templates/" rel="noopener noreferrer"&gt;bicep/templates&lt;/a&gt; folder, these are all linked and deployed from the &lt;a href="https://github.com/manukanne/tutorial-az-func-iacbicep/main.bicep" rel="noopener noreferrer"&gt;main.bicep&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;For more detailed information, please checkout my &lt;a href="https://dev.to/manukanne/azure-infrastructure-as-code-deploy-an-azure-function-using-bicep-1i04" rel="nofollow"&gt;blog post&lt;/a&gt; 😃&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/manukanne/tutorial-az-func-iac.img/azure-function-overview.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fmanukanne%2Ftutorial-az-func-iac.img%2Fazure-function-overview.png" alt="Azure Function Resources Overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Perquisites&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Azure Account with an active subscription. In case you do not have an Azure Account, go ahead and create one for free &lt;a href="https://azure.microsoft.com/en-us/free/" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" rel="nofollow noopener noreferrer"&gt;Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install" rel="nofollow noopener noreferrer"&gt;Bicep Tools&lt;/a&gt; for Azure CLI and VS Code&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How to deploy the templates&lt;/h3&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Create a parameter file&lt;/h4&gt;

&lt;/div&gt;

&lt;p&gt;The example &lt;a href="https://github.com/manukanne/tutorial-az-func-iacexample-deployment-parameters.json" rel="noopener noreferrer"&gt;parameter file&lt;/a&gt; looks like this:&lt;/p&gt;

&lt;div class="highlight highlight-source-json notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;{
    &lt;span class="pl-ent"&gt;"$schema"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
    &lt;span class="pl-ent"&gt;"contentVersion"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;1.0.0.0&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;,
    &lt;span class="pl-ent"&gt;"parameters"&lt;/span&gt;: {
      &lt;span class="pl-ent"&gt;"storageAccountName"&lt;/span&gt;: {
        &lt;span class="pl-ent"&gt;"value"&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;stvm&amp;lt;storage-account-name&amp;gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/manukanne/tutorial-az-func-iac" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>azure</category>
      <category>devops</category>
      <category>cloud</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Serverless Thumbnail Generation with Azure Computer Vision</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Sun, 17 Apr 2022 00:43:56 +0000</pubDate>
      <link>https://forem.com/manukanne/serverless-thumbnail-generation-with-azure-computer-vision-2d7c</link>
      <guid>https://forem.com/manukanne/serverless-thumbnail-generation-with-azure-computer-vision-2d7c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this guide, I would like to introduce a pre-build AI service called Azure Cognitive Service, in particular Azure Computer Vision with the Thumbnail Generation API.&lt;br&gt;
As surely known a thumbnail is simply a smaller version of the original image, in web applications thumbnails are used in many places like for displaying product images etc. Because of the fact that thumbnails are smaller they need less bandwidth than the original images and speed up the loading of websites.&lt;/p&gt;

&lt;p&gt;Azure Computer Vision is part of Azure Cognitive Services. But what are Azure Cognitive Services? At a glance, Azure Cognitive Services offers the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speech

&lt;ul&gt;
&lt;li&gt;Speech to text&lt;/li&gt;
&lt;li&gt;Text to speech&lt;/li&gt;
&lt;li&gt;Speech translation&lt;/li&gt;
&lt;li&gt;Speaker recognition&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Languages

&lt;ul&gt;
&lt;li&gt;Entity recognition&lt;/li&gt;
&lt;li&gt;Sentiment analysis&lt;/li&gt;
&lt;li&gt;Question Answering&lt;/li&gt;
&lt;li&gt;Conversational language understanding&lt;/li&gt;
&lt;li&gt;Translator&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Vision

&lt;ul&gt;
&lt;li&gt;Computer Vision&lt;/li&gt;
&lt;li&gt;Custom Vision&lt;/li&gt;
&lt;li&gt;Face API&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Decision

&lt;ul&gt;
&lt;li&gt;Anomaly Detector&lt;/li&gt;
&lt;li&gt;Content Moderator&lt;/li&gt;
&lt;li&gt;Personalizer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OpenAI

&lt;ul&gt;
&lt;li&gt;OpenAI Service&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a nutshell, Azure Cognitive Services offer various pre-build AI services, one of which is Azure Computer Vision. Azure Computer Vision offers much more functionality than just thumbnail generation, but we'll leave that out for now (this maybe a topic for another blog post 😀).&lt;/p&gt;

&lt;p&gt;For more details on Azure Cognitive Services, please checkout the &lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/cognitive-services/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why should we use Azure Computer Vision for Thumbnail Generation?
&lt;/h2&gt;

&lt;p&gt;Creating thumbnails can sometimes be quite challenging and there are various tutorials for countless programming languages that cover this topic. Azure Computer Vision does the following things for us when creating the thumbnail:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove distracting elements from the image and identify the area of interest—the area of the image in which the main object(s) appears.&lt;/li&gt;
&lt;li&gt;Crop the image based on the identified area of interest.&lt;/li&gt;
&lt;li&gt;Change the aspect ratio to fit the target thumbnail dimensions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Especially the &lt;em&gt;Smart Cropping&lt;/em&gt;, i.e. the detection and removal of distracting elements, is an extremely useful feature. Imagine you implement your own thumbnail creation algorithm and the center is always cropped out, but the area of interest is outside the center. So the algorithm would crop something that is actually relevant and that's where &lt;em&gt;Smart Cropping&lt;/em&gt; comes to the rescue!&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Azure Account with an active subscription. In case you do not have an Azure Account, go ahead and create one for free &lt;a href="https://azure.microsoft.com/en-us/free/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Azure CLI, you can either install the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" rel="noopener noreferrer"&gt;Azure CLI locally&lt;/a&gt; or use the &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-shell/overview" rel="noopener noreferrer"&gt;Azure Cloud Shell&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Computer Vision Deployment
&lt;/h3&gt;

&lt;p&gt;Create a resource group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; az group create &lt;span class="nt"&gt;-l&lt;/span&gt; &amp;lt;location&amp;gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &amp;lt;name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the &lt;em&gt;Computer Vision&lt;/em&gt; resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cognitiveservices account create &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; &amp;lt;computer-vision-resource-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--resource-group&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--kind&lt;/span&gt; ComputerVision &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--sku&lt;/span&gt; F0 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--location&lt;/span&gt; &amp;lt;location&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ For the pricing tier, instead of F0 (= free tier) you can also specify S1 (= Standard S1).&lt;/p&gt;

&lt;p&gt;⚠️ Only one free tier can be deployed at a time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Grab the endpoint URL of your Computer Vision service via the Azure Portal:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwfi4n29uf220jmws4k6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwfi4n29uf220jmws4k6.png" alt="Grab the endpoint url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieve the access keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cognitiveservices account keys list &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &amp;lt;computer-vision-resource-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &amp;lt;resource-group&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ In case you want to regenerate or rotate your keys, you can use the following command:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cognitiveservices account keys regenerate &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--key-name&lt;/span&gt; &amp;lt;Key1, Key2&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &amp;lt;computer-vision-resource-name&amp;gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &amp;lt;resource-group&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating of Thumbnails via the Azure Computer Vision API
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Requirements and limitations of the Thumbnail API
&lt;/h4&gt;

&lt;p&gt;Before we start calling the endpoint, here are some image requirements and limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image file size must be less than 4MB&lt;/li&gt;
&lt;li&gt;Image dimensions should be greater than 50 x 50&lt;/li&gt;
&lt;li&gt;Supported image formats

&lt;ul&gt;
&lt;li&gt;JPEG&lt;/li&gt;
&lt;li&gt;PNG&lt;/li&gt;
&lt;li&gt;GIF&lt;/li&gt;
&lt;li&gt;BMP&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  How to call the API
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Request Parameters:
&lt;/h5&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;width&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;Width of the thumbnail. It must be between 1 and 1024. Recommended minimum of 50.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;height&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;Height of the thumbnail. It must be between 1 and 1024. Recommended minimum of 50.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;smartCropping (optional)&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;Boolean flag for enabling smart cropping.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;model-version (optional)&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Optional parameter to specify the version of the AI model. The default value is "latest".&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h5&gt;
  
  
  Request Header:
&lt;/h5&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Media type of the body sent to the API.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ocp-Apim-Subscription-Key&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;Subscription key which provides access to this API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h5&gt;
  
  
  Request Body:
&lt;/h5&gt;

&lt;p&gt;The Thumbnail API supports the following content types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application/json&lt;/li&gt;
&lt;li&gt;application/octet-stream&lt;/li&gt;
&lt;li&gt;multipart/form-data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;application/json:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"http://example.com/images/test.jpg"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;application/octet-stream:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Binary image data]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;multipart/form-data:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Binary image data]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ℹ️ The above section is an excerpt from the official documentation. For more details, please checkout the official &lt;a href="https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/concept-generating-thumbnails" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Example requests
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;application/json:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'https://&amp;lt;computer-vision-resource-name&amp;gt;.cognitiveservices.azure.com/vision/v3.2/generateThumbnail?width=200&amp;amp;height=200&amp;amp;smartCropping=true&amp;amp;model-version=latest'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Ocp-Apim-Subscription-Key: &amp;lt;api-key&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{
    "url":"http://example.com/images/test.jpg"
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;application/octet-stream:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'https://&amp;lt;computer-vision-resource-name&amp;gt;.cognitiveservices.azure.com/vision/v3.2/generateThumbnail?width=200&amp;amp;height=200&amp;amp;smartCropping=true&amp;amp;model-version=latest'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/octet-stream'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Ocp-Apim-Subscription-Key: &amp;lt;api-key&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--data-binary&lt;/span&gt; &lt;span class="s1"&gt;'@&amp;lt;path-to-image&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;multipart/form-data:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="s1"&gt;'https://&amp;lt;computer-vision-resource-name&amp;gt;.cognitiveservices.azure.com/vision/v3.2/generateThumbnail?width=200&amp;amp;height=200&amp;amp;smartCropping=true&amp;amp;model-version=latest'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: multipart/form-data'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Ocp-Apim-Subscription-Key: &amp;lt;api-key&amp;gt;'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--form&lt;/span&gt; &lt;span class="s1"&gt;'img=@"&amp;lt;path-to-image&amp;gt;"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For my example requests I used the following image:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzl5vzptficdkn165bbxd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzl5vzptficdkn165bbxd.jpg" alt="Example image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ The image is taken from &lt;a href="https://unsplash.com/" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;. Unsplash is really awesome and offers freely-usable images. You should definitely check it out!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the image with &lt;em&gt;Smart Cropping&lt;/em&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m2urju8sxdpbf2b6c7w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m2urju8sxdpbf2b6c7w.jpeg" alt="Example image with smart cropping enabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is the image without &lt;em&gt;Smart Cropping&lt;/em&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73lbnmdx2nsb6kl035y0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73lbnmdx2nsb6kl035y0.jpeg" alt="Example image without smart cropping"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can clearly see in the picture without &lt;em&gt;Smart Cropping&lt;/em&gt; parts of the keyboard are missing, as well the right arm was cropped away. Also in the left corner the plant is still visible. In the picture with &lt;em&gt;Smart Cropping&lt;/em&gt; the keyboard, as well as both arms, are nicely visible and the plant in the left corner has been completely removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;As you could hopefully see, Azure Computer Vision thumbnail generation is extremely easy to use and offers useful features like smart cropping. But how much does the API cost?&lt;/p&gt;

&lt;p&gt;Azure Computer Vision is a fully managed serverless service and pricing is "pay-as-you-go", in addition Microsoft offers a free tier for development purposes. The Computer Vision service for thumbnail generation is very affordable, &lt;strong&gt;1000 transactions costs around $1&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm362w38mg1ajx3flm3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm362w38mg1ajx3flm3y.png" alt="Example calculation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Disclaimer: This is an example configuration. Other prices may apply depending on configuration and region. For more precise estimation, I highly recommend using the &lt;a href="https://azure.microsoft.com/en-us/pricing/calculator/" rel="noopener noreferrer"&gt;Azure Pricing Calculator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ℹ️ For enterprise scenarios with high volumes, Azure also offers a &lt;em&gt;Committed Tier&lt;/em&gt;, where fixed contingents can be purchased at a reduced price. For more details, checkout the official pricing page for &lt;a href="https://azure.microsoft.com/en-us/pricing/details/cognitive-services/computer-vision/#pricing" rel="noopener noreferrer"&gt;Azure Computer Vision&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope I could bring you a little bit closer to Azure Computer Vision for thumbnail generation. It really is an incredible service that greatly simplifies thumbnail creation and can make a developer's life immensely easier with features like Smart Cropping. Additionally, the service doesn't cost a fortune either 😉&lt;/p&gt;

&lt;p&gt;Thanks for reading, let me know your thoughts on this feature! &lt;/p&gt;

</description>
      <category>azure</category>
      <category>webdev</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Tutorial: Create an Azure Blob Storage with SFTP integration</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Wed, 30 Mar 2022 01:16:03 +0000</pubDate>
      <link>https://forem.com/manukanne/tutorial-create-an-azure-blob-storage-with-sftp-integration-cd6</link>
      <guid>https://forem.com/manukanne/tutorial-create-an-azure-blob-storage-with-sftp-integration-cd6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Azure has announced a SFTP feature for Storage Accounts. Currently, the feature is still in preview and should therefore not be used for production workloads until it reaches GA.&lt;/p&gt;

&lt;p&gt;The new Azure Storage Account SFTP feature provides a full managed PaaS service. Before that, an SFTP service had to be provided in other ways such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom implementation&lt;/strong&gt;: Development of a custom service that provides the SFTP functions, which then persists the files in a blob storage. For this use case Microsoft offers a template, consisting of an Azure Storage Account fileshare and a container instance. For more information, please checkout this &lt;a href="https://docs.microsoft.com/en-us/samples/azure-samples/sftp-creation-template/sftp-on-azure/" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machine&lt;/strong&gt;: Deploy a VM with a SFTP service, either Windows or Linux. Especially for small use cases, this variant could be a overkill and depending on the configuration, this solution is also quite expensive. Furthermore, the administration overhead is significantly higher than with the integrated SFTP option.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Advantages of the PaaS variant: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Easy to setup &amp;amp; use&lt;/li&gt;
&lt;li&gt;✅ Fully managed serverless service &lt;/li&gt;
&lt;li&gt;✅ Extremely cheap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would like to emphasize the last point in particular. Azure Blob Storage is an extremely cost-effective storage option, here is an example calculation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage Account Configuration&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration Property Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;West Europe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type&lt;/td&gt;
&lt;td&gt;Block Blob Storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance Tier&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage Account Type&lt;/td&gt;
&lt;td&gt;General Purpose V2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access Tier&lt;/td&gt;
&lt;td&gt;Hot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redundancy&lt;/td&gt;
&lt;td&gt;LRS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Storage Account Pricing&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Capacity&lt;/td&gt;
&lt;td&gt;100 GB&lt;/td&gt;
&lt;td&gt;1.76 €&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write Operations&lt;/td&gt;
&lt;td&gt;10 x 10.000&lt;/td&gt;
&lt;td&gt;0.49 €&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List and create Container Operation&lt;/td&gt;
&lt;td&gt;10x 10.000&lt;/td&gt;
&lt;td&gt;0.04 €&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Retrieval&lt;/td&gt;
&lt;td&gt;1000 GB&lt;/td&gt;
&lt;td&gt;0.0 €&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Write&lt;/td&gt;
&lt;td&gt;1000 GB&lt;/td&gt;
&lt;td&gt;0.0 €&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Support&lt;/td&gt;
&lt;td&gt;Included&lt;/td&gt;
&lt;td&gt;0.0 €&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Monthly cost: &lt;strong&gt;2.78 €&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;As illustrated here, Azure Blob Storage is really affordable! In the example you get for not even 3€ a complete managed storage with many different features like SFTP support and many more!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Disclaimer: This is an example configuration. Storage accounts are "pay as you go" and other prices may apply depending on configuration and region. For more precise estimation, I highly recommend using the &lt;a href="https://azure.microsoft.com/en-us/pricing/calculator/" rel="noopener noreferrer"&gt;&lt;em&gt;Azure Pricing Calculator&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Azure Account with an active subscription. In case you do not have an Azure Account, go ahead and create one for free &lt;a href="https://azure.microsoft.com/en-us/free/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Azure CLI, you can either install the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" rel="noopener noreferrer"&gt;Azure CLI locally&lt;/a&gt; or use the &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-shell/overview" rel="noopener noreferrer"&gt;Azure Cloud Shell&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ If the Azure Cloud Shell is used, then the command az login is not needed. In the Cloud shell you are automatically logged in with the current user.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Enable the SFTP preview feature
&lt;/h3&gt;

&lt;p&gt;In order to use this new feature, it has to be activated in advance for the respective subscription:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fl367fxrvwgazgxaw9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0fl367fxrvwgazgxaw9l.png" alt="Register the SFTP support in Azure Blob Storage feature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;In the search bar, search for &lt;em&gt;Subscriptions&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Select your subscription (in my case, my subscription is named &lt;em&gt;Pay-As-You-Go&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Inside your subscription, search for &lt;em&gt;Preview Features&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Inside the available features, search for "sftp" and register the &lt;em&gt;SFTP support in Azure Blob Storage&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Azure CLI&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Install the storage-preview extension:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az extension add &lt;span class="nt"&gt;-n&lt;/span&gt; storage-preview


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Azure login:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az login


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;List available subscriptions and set active azure subscription:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az account list &lt;span class="nt"&gt;--all&lt;/span&gt;
az account &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--subscription&lt;/span&gt; &amp;lt;subscription-id&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Enable SFTP feature:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az feature register &lt;span class="nt"&gt;--namespace&lt;/span&gt; Microsoft.Storage &lt;span class="nt"&gt;--name&lt;/span&gt; AllowSFTP 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Verify feature registration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az feature show &lt;span class="nt"&gt;--namespace&lt;/span&gt; Microsoft.Storage &lt;span class="nt"&gt;--name&lt;/span&gt; AllowSFTP 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Create and configure the Azure Storage Account
&lt;/h2&gt;

&lt;p&gt;Microsoft provides a &lt;a href="https://github.com/Azure/azure-quickstart-templates/tree/master/quickstarts/microsoft.storage/storage-sftp" rel="noopener noreferrer"&gt;demo template&lt;/a&gt; , in order to deploy the template click on the following button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2Fquickstarts%2Fmicrosoft.storage%2Fstorage-sftp%2Fazuredeploy.json" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fazure-quickstart-templates%2Fmaster%2F1-CONTRIBUTION-GUIDE%2Fimages%2Fdeploytoazure.svg%3Fsanitize%3Dtrue" alt="Deploy To Azure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this template we are ready to go and can test the SFTP feature. But of course we will also deploy everything from scratch:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create the Azure Storage Account:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account create &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;storage-account-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-l&lt;/span&gt; &amp;lt;azure-location&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--sku&lt;/span&gt; Standard_LRS &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--https-only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--hierarchical-namespace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--kind&lt;/span&gt; StorageV2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Enable SFTP:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account update &lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--enable-sftp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Create an Azure Storage Container:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage container create &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;container-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &amp;lt;storage-account-name&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Create local user for SFTP access:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account local-user create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;local-user-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--home-directory&lt;/span&gt; &amp;lt;home-dir&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--permission-scope&lt;/span&gt; &lt;span class="nv"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;permissions&amp;gt; &lt;span class="nv"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;blob resource-name&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;container-name&amp;gt; &lt;span class="se"&gt;\ &lt;/span&gt;
&lt;span class="nt"&gt;--ssh-authorized-key&lt;/span&gt; &lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;ssh-key&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--has-ssh-key&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--has-ssh-password&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Authentication:&lt;/em&gt;&lt;br&gt;
For authentication, there are two options available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Password&lt;/li&gt;
&lt;li&gt;SSH Key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to create or regenerate a password, use this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account local-user regenerate-password &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;local-user-name&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There are many ways to generate SSH key pairs. Just use your preferred tool, alternatively the Azure CLI can be used:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az sshkey create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;ssh-key-name&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;resource-group&amp;gt;"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command creates a new SSH key Azure resource:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggxrbp3hp49o5osfdcpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggxrbp3hp49o5osfdcpu.png" alt="Azure SSH key resource"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more details, checkout the &lt;a href="https://docs.microsoft.com/en-us/azure/virtual-machines/ssh-keys-azure-cli#generate-new-keys" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ While you can enable both forms of authentication, SFTP clients can connect by using only one of them. Multifactor authentication, whereby both a valid password and a valid public and private key pair are required for successful authentication is not supported.&lt;/p&gt;

&lt;p&gt;⚠️ You can't retrieve the generated password later, so make sure to copy the password, and then store it in a place where you can find it. If you lose this password, you'll have to generate a new one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Home directory:&lt;/em&gt;&lt;br&gt;
Home directory is only the initial directory that the connecting local user is placed in. Local users can navigate to any other path in the container they are connected to if they have the appropriate container permissions.&lt;br&gt;
Format: &lt;em&gt;container/folder/...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Available container permissions:&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;tr&gt;
        &lt;th&gt;Permission&lt;/th&gt;
        &lt;th&gt;Permission Code&lt;/th&gt;
        &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Read&lt;/td&gt;
        &lt;td&gt;r&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Read all file contents&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Write&lt;/td&gt;
        &lt;td&gt;w&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Upload file&lt;/li&gt;
                &lt;li&gt;Create directory&lt;/li&gt;
                &lt;li&gt;Upload directories&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;List&lt;/td&gt;
        &lt;td&gt;l&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;List contents within container&lt;/li&gt;
                &lt;li&gt;List contents within directories&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Delete&lt;/td&gt;
        &lt;td&gt;d&lt;/td&gt;
        &lt;td&gt;
            &lt;li&gt;Delete files/directories&lt;/li&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Create&lt;/td&gt;
        &lt;td&gt;c&lt;/td&gt;
        &lt;td&gt;
            &lt;ul&gt;
                &lt;li&gt;Upload file if file doesn't exist&lt;/li&gt;
                &lt;li&gt;Create directory if it doesn't exist&lt;/li&gt;
                &lt;li&gt;Create directories&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can also specify multiple permission scopes: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nt"&gt;--permission-scope&lt;/span&gt; &lt;span class="nv"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rw &lt;span class="nv"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;blob resource-name&lt;span class="o"&gt;=&lt;/span&gt;container1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--permission-scope&lt;/span&gt; &lt;span class="nv"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rwd &lt;span class="nv"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;file resource-name&lt;span class="o"&gt;=&lt;/span&gt;share2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Connect via SFTP to the Azure Storage Account
&lt;/h2&gt;

&lt;p&gt;I will briefly go over the creation of the SFTP user again here. Lets get started! In my case, I created the following SFTP user:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account local-user create &lt;span class="nt"&gt;--account-name&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; mka &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--home-directory&lt;/span&gt; mystoragecontainer &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--permission-scope&lt;/span&gt; &lt;span class="nv"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rwcdl &lt;span class="nv"&gt;service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;blob resource-name&lt;span class="o"&gt;=&lt;/span&gt;mystoragecontainer &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--has-ssh-password&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ For the sake of simplicity, I only use password authentication. As mentioned above you can also choose SSH key authentication or even both (please note that you can't use both at the same time, you can authenticate either via password or SSH key).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to obtain the password of the newly created user, please use this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account local-user regenerate-password &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-n&lt;/span&gt; mka 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Do not forget to copy the password after creating it, it cannot be requested again. If you lose the password, you must create a new one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To connect to the storage account we need the blob primary endpoint. This can be obtained with the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account show &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The previous command gives the general info about the storage account. Search for the section "primaryEndoints" and copy the "blob" URL without the prefix https or http(for example .blob.core.windows.net):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nl"&gt;"primaryEndpoints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"blob"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;storage-account-name&amp;gt;.blob.core.windows.net/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dfs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;storage-account-name&amp;gt;.dfs.core.windows.net/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;storage-account-name&amp;gt;.file.core.windows.net/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"internetEndpoints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"microsoftEndpoints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"queue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;storage-account-name&amp;gt;.queue.core.windows.net/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"table"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;storage-account-name&amp;gt;.table.core.windows.net/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;storage-account-name&amp;gt;.z6.web.core.windows.net/"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you can connect to the storage account with your &lt;em&gt;**preferred SFTP client&lt;/em&gt;*. In my case I use PowerShell with OpenSSH and password authentication:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

sftp &amp;lt;storage-account&amp;gt;.mka@&amp;lt;storage-account&amp;gt;.blob.core.windows.net


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;ℹ️ The username of the SSH user is in following format: &lt;em&gt;storage-account.sftp-user-name&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ℹ️ You might be prompted to trust a host key. During the public preview, valid host keys are published &lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-host-keys" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After that you will be asked to authenticate yourself, just enter the password here.&lt;/p&gt;

&lt;p&gt;After successfully authenticating, a file can be uploaded with this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

put &amp;lt;path-to-file&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Verify the file upload either directly within the SFTP client or via the following Azure CLI command:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Retrieve Azure Storage Account Keys (for authentication):&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage account keys list &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &amp;lt;resource-group&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result of this should look something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"creationTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-03-27T17:51:51.501304+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keyName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"key1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FULL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;key-value-1&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"creationTime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-03-27T17:51:51.501304+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"keyName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"key2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FULL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;key-value-2&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Simply copy one of the keys.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;List files:&lt;/em&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

az storage fs file list &lt;span class="nt"&gt;-f&lt;/span&gt; &amp;lt;container-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--recursive&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &amp;lt;storage-account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-key&lt;/span&gt; &amp;lt;insert-previous-copied-key-here&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The output should look something like this:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contentLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;53759&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"etag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x8DA11E2F03CABAB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$superuser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"isDirectory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lastModified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-03-30T20:19:21"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;my-file&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$superuser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rw-r-----"&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;As mentioned before, Azure Storage Accounts are a very cost effective option to store files that now offer SFTP integration.&lt;br&gt;
Since this variant is a so-called serverless, there are many exciting use-cases! Especially many legacy systems that work with files often offer an SFTP upload. These programs can now upload the files directly to the cloud and once the files are in the cloud they can be easily processed further, e.g. with an Azure function that processes the uploaded files with an "on-file-created" trigger.&lt;/p&gt;

&lt;p&gt;If you made it this far, thanks for reading! Let me know your thoughts on this new feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-account-overview" rel="noopener noreferrer"&gt;Storage Accounts Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support" rel="noopener noreferrer"&gt;SSH File Transfer Protocol (SFTP) support for Azure Blob Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-support-how-to?tabs=azure-portal" rel="noopener noreferrer"&gt;Connect to Azure Blob Storage by using the SSH File Transfer Protocol (SFTP)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-host-keys" rel="noopener noreferrer"&gt;Host keys for SSH File Transfer Protocol (SFTP) support for Azure Blob Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/secure-file-transfer-protocol-known-issues" rel="noopener noreferrer"&gt;Limitations and known issues with SSH File Transfer Protocol (SFTP) support for Azure Blob Storage&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>sftp</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Azure Functions and FastAPI</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Thu, 24 Mar 2022 22:59:58 +0000</pubDate>
      <link>https://forem.com/manukanne/azure-functions-and-fastapi-14b6</link>
      <guid>https://forem.com/manukanne/azure-functions-and-fastapi-14b6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Azure Functions are a great cloud service that enables the implementation of event-driven architectures like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building a web API&lt;/li&gt;
&lt;li&gt;Process file uploads&lt;/li&gt;
&lt;li&gt;Scheduled tasks&lt;/li&gt;
&lt;li&gt;Processing events or queues&lt;/li&gt;
&lt;li&gt;and much more!
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsyj56u7aj6lkfs0lol0z.png" alt="Azure Function Overview"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blogpost I want to focus on the first point, building a web API with Azure Functions. Azure Functions offer several hosting options, but probably the most common hosting plan chosen is the consumption plan, better known as serverless plan.&lt;/p&gt;

&lt;p&gt;While it is absolutely possible to create a web API with the built-in Azure function framework features I like to show how to use Azure Functions in combination with FastAPI.&lt;br&gt;
For example, a vanilla Azure Function with Python might look like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-http-header&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some-value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;req_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req_body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
             &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please pass a name on the query string or in the request body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;To learn more about Azure Functions check out the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview" rel="noopener noreferrer"&gt;Azure Functions Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference" rel="noopener noreferrer"&gt;Azure Functions developer guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-python" rel="noopener noreferrer"&gt;Azure Function Python developer guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But why should we use FastAPI? FastAPI offers many useful features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast:&lt;/strong&gt; Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). One of the fastest Python frameworks available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast to code:&lt;/strong&gt; Increase the speed to develop features by about 200% to 300%. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer bugs:&lt;/strong&gt; Reduce about 40% of human (developer) induced errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive:&lt;/strong&gt; Great editor support. Completion everywhere. Less time debugging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy:&lt;/strong&gt; Designed to be easy to use and learn. Less time reading docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short:&lt;/strong&gt; Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust:&lt;/strong&gt; Get production-ready code. With automatic interactive documentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standards-based:&lt;/strong&gt; Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to the features already mentioned, FastAPI also offers the following advantages over vanilla Azure Functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model binding for requests and response with additional model validation features provided by &lt;a href="https://pydantic-docs.helpmanual.io/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Dependency management and the creation of reusable components (like common query parameters).&lt;/li&gt;
&lt;li&gt;Open API definition with built-in /docs route&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more details please visit the official &lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Install the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash#install-the-azure-functions-core-tools" rel="noopener noreferrer"&gt;Azure Function Core Tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.9.0&lt;/li&gt;
&lt;li&gt;Azure Subscription (optional) &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Setup the local development environment
&lt;/h3&gt;

&lt;p&gt;Create the Function project:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

func init &amp;lt;your_function_project_name&amp;gt; --worker-runtime python


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Navigate into your newly created function project and create a HTTP function:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

func new --template "Http Trigger" --name main


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In order to start the Azure Function, please use this command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

func start --python


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After creating the project, open the project in the code editor of your choice and edit the following files as follows:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scriptFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"__init__.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bindings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"authLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"httpTrigger"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"req"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"methods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"patch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"delete"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"route"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/{*route}"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"out"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$return"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;em&gt;function.json&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This endpoint becomes the main entry point into the application. For this route to match all patterns the "route" property must be modified as shown above. This way all incoming requests will be handled by this route. The processing of the web requests is managed by FastAPI.&lt;/p&gt;

&lt;p&gt;Additionally the &lt;strong&gt;allowed HTTP methods&lt;/strong&gt; like GET, POST etc. &lt;strong&gt;have to be specified&lt;/strong&gt;. If a HTTP method is used that was not specified, the Azure function throws a "method not allowed" exception.&lt;br&gt;
Furthermore, the host.json file must also be updated as follows:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"applicationInsights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"samplingSettings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"isEnabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"excludedTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Request"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensionBundle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Microsoft.Azure.Functions.ExtensionBundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[2.*, 3.0.0)"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"routePrefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;em&gt;host.json&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For more details, please checkout the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-python?tabs=asgi%2Cazurecli-linux%2Capplication-level#web-frameworks" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's write some code
&lt;/h2&gt;

&lt;p&gt;The snippet from the official documentation looks like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fastapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/hello/{name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,):&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;AsgiMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The code shown above glues the Azure Function and FastAPI together. After this snippet all features of the standard FastAPI framework can be used.&lt;/p&gt;

&lt;p&gt;For example my implementation looks like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.responses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JSONResponse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;routers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;utilities.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApiException&lt;/span&gt;


&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
This is a sample API based on Azure Functions and FastAPI.

This API is used to illustrate how a potential API with Azure Functions and FastAPI could look like, it is a demo API only.
I hope you like it and help you to build awesome projects based on these great frameworks!

## Products
* Add products
* Retrieve products
* Retrieve a specific product by ID
* Update existing products
* Delete products by ID
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Azure Function Demo FastAPI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Manuel Kanetscheider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.to/manukanne&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;me@manuelkanetscheider.net&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;license_info&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MIT License&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://github.com/manukanne/tutorial-az-func-fastapi/blob/main/LICENSE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Add additional api routers here
&lt;/span&gt;

&lt;span class="nd"&gt;@app.exception_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generic_api_exception_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ApiException&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Generic API exception handler. 
    Ensures that all thrown excpetions of the custom type API Excpetion are returned 
    in a unified exception JSON format (code and description).    
    Args:
        request (Request): HTTP Request
        ex (ApiException): Thrown exception

    Returns:
        JSONResponse: Returns the exception in JSON format
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;JSONResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Azure function entry point.
    All web requests are handled by FastAPI.
    Args:
        req (func.HttpRequest): Request
        context (func.Context): Azure Function Context

    Returns:
        func.HttpResponse: HTTP Response
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsgiMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;And the implementation of the example product routes looks like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DatabaseManagerBase&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_db&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;utilities.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EntityNotFoundException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ApiException&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;schemas&lt;/span&gt;

&lt;span class="n"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;APIRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@router.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Creates a product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductCreate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseManagerBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a product:

    - **title**: Title of the product
    - **description**: Description of the product
    - **purch_price**: The purch price of the product
    - **sales_price**: The sales price of the product
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Products: Add product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;


&lt;span class="nd"&gt;@router.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieves all prodcuts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieves all available products from the API&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseManagerBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product: Fetch products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_products&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;


&lt;span class="nd"&gt;@router.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/{product_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieve a product by ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieves a specific product by ID, if no product matches the filter criteria a 404 error is returned&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseManagerBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Prouct: Fetch product by id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;EntityNotFoundException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unable to retrieve product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                      &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product with the id &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; does not exist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;


&lt;span class="nd"&gt;@router.patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/{product_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Patches a product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product_update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductPartialUpdate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseManagerBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt; 
    Patches a product, this endpoint allows to update single or multiple values of a product

    - **title**: Title of the product
    - **description**: Description of the product
    - **purch_price**: The purch price of the product
    - **sales_price**: The sales price of the product
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product: Update product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exclude_unset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ApiException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please specify at least one property!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;product_update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;EntityNotFoundException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unable to update product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product with the id &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; does not exist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;


&lt;span class="nd"&gt;@router.delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/{product_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deletes a product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deletes a product permanently by ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DatabaseManagerBase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product: Delete product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;I won't go into the details of the technical implementation of my FastAPI routes here, that's a topic for maybe another blog post. Nevertheless, you can download all the documented source code in the linked GitHub repo.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Testing the API
&lt;/h2&gt;

&lt;p&gt;You can test the API I developed either via the provided Postman Collection or via the built-in documentation of FastAPI (the docs are provided via the route /docs).&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0qzxshhixg0964ghk3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0qzxshhixg0964ghk3r.png" alt="FastAPI docs"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploy to Azure
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This step requires an Azure Account. In case you do not have an Azure Account you can go ahead and create an account for free &lt;a href="https://azure.microsoft.com/en-us/free/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The repository contains an ARM template. An ARM template contains all the necessary information to deploy resources in Azure, in this case it contains the information to deploy an Azure Function including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage Account&lt;/li&gt;
&lt;li&gt;Serverless Hosting Plan&lt;/li&gt;
&lt;li&gt;Function App&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information about ARM templates, please checkout the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Also worth mentioning is the new technology "Bicep". It is similar to ARM templates but offers a declarative approach. Bicep is comparable to Terraform, but unlike Terraform, Bicep can only be used for Azure. For more information about Bicep, please checkout the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The provided ARM template was originally developed by Ben Keen, for more information about this ARM template, please checkout his &lt;a href="https://benalexkeen.com/automated-deployment-of-serverless-python-web-apis-using-azure-functions-and-azure-devops/" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Deploy the ARM template and the function code using the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli" rel="noopener noreferrer"&gt;Azure CLI&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

az deployment group create --resource-group &amp;lt;resource-group&amp;gt; --template-file .\az-func-template.json --parameters appName='&amp;lt;your_app_name&amp;gt;' storageAcctName='&amp;lt;your_storage_account_name&amp;gt;' hostingPlanName='&amp;lt;your_hosting_plan_name&amp;gt;'

func azure functionapp publish &amp;lt;your_function_app_name&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Before executing the commands, please make sure that you have called "az login"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Azure Functions enable you to create scalable and cost-effective web APIs. With FastAPI, the functionality of Azure functions can be extended tremendously, making it easy to create complex APIs.&lt;/p&gt;

&lt;p&gt;Thank you for reading, I hope you enjoyed it!&lt;/p&gt;

&lt;p&gt;Link to the full source code on GitHub:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/manukanne" rel="noopener noreferrer"&gt;
        manukanne
      &lt;/a&gt; / &lt;a href="https://github.com/manukanne/tutorial-az-func-fastapi" rel="noopener noreferrer"&gt;
        tutorial-az-func-fastapi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Tutorial: Azure Function with FastAPI&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This project is a demonstration of how Azure Functions can be used in combination with FastAPI.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Description&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Demo API with the following endpoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product
&lt;ul&gt;
&lt;li&gt;Create&lt;/li&gt;
&lt;li&gt;Read all products&lt;/li&gt;
&lt;li&gt;Read a specific product&lt;/li&gt;
&lt;li&gt;Patch product data&lt;/li&gt;
&lt;li&gt;Delete a product&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should be noted that this is only a demo API. This API does not use a real database and therefore only uses a very simplified database manager with an "InMemory" database.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Getting started&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Prerequisites&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Install the &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash#install-the-azure-functions-core-tools" rel="nofollow noopener noreferrer"&gt;Azure Function Core Tools&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Python 3.9.0&lt;/li&gt;
&lt;li&gt;Azure Subscription (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, create  a python virtual environment, activate it and install the requirements.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Start the function&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;func start --python
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;In order to start the Azure Function via the Azure Function Core Tools (CLI) a activated virtual environment is required.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After starting Azure Functions you can access the documentation via this link:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;http://localhost:7071/docs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Deploy to Azure:&lt;/h2&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;This step requires an Azure Account…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/manukanne/tutorial-az-func-fastapi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>azure</category>
      <category>python</category>
      <category>webdev</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>AtlasHackathon - A Quiz API using MongoDB and FastAPI</title>
      <dc:creator>Manuel Kanetscheider </dc:creator>
      <pubDate>Wed, 12 Jan 2022 20:06:47 +0000</pubDate>
      <link>https://forem.com/manukanne/atlashackathon-a-quiz-api-using-mongodb-and-fastapi-2c45</link>
      <guid>https://forem.com/manukanne/atlashackathon-a-quiz-api-using-mongodb-and-fastapi-2c45</guid>
      <description>&lt;p&gt;I created this application to take part in MongoDB Atlas Hackathon.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Idea
&lt;/h3&gt;

&lt;p&gt;I wanted to create a quiz API. The API allows to create quizzes and subsequently also to submit a quiz and calculate the achieved points. Quizzes can also be tagged with categories (e.g. fun, programming, general knowledge etc.).&lt;br&gt;
The API also includes authentication using OAUTH2, the user data as well as all other data is stored in the MongoDB cloud atlas database.&lt;/p&gt;

&lt;p&gt;Core functions at a glance: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication/ Authorization using OAuth2&lt;/li&gt;
&lt;li&gt;CRUD Operations for quiz categories&lt;/li&gt;
&lt;li&gt;CRUD Operations for quizzes

&lt;ul&gt;
&lt;li&gt;Including Quiz submition and calulating the total and reached points &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Also, the project is fully covered by unit tests&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;This project was built on top of the following tech-stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.9&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastApi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/cloud/atlas" rel="noopener noreferrer"&gt;MongoDB Cloud Atlas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.mongoengine.org/index.html" rel="noopener noreferrer"&gt;MongoEngine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can test the API with the included &lt;a href="https://github.com/manukanne/cloudatlas-quiz-api#executing-program" rel="noopener noreferrer"&gt;Postman collection&lt;/a&gt;: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j0j6gypuea83uo8bp7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8j0j6gypuea83uo8bp7o.png" alt="Postman Collection"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before using the collection, please create a Postman environment:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7vh03sgiciwa3fg13ci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7vh03sgiciwa3fg13ci.png" alt="Postman environment configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;api_url: URL to the API&lt;/li&gt;
&lt;li&gt;username: email of your user&lt;/li&gt;
&lt;li&gt;password: plain text password of your user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After this step the Access Token can be obtained:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mvjxougtwviw53ftlo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mvjxougtwviw53ftlo1.png" alt="Optain access token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alternatively, the API can also be tested with the built-in &lt;a href="https://fastapi.tiangolo.com/features/#automatic-docs" rel="noopener noreferrer"&gt;Swagger UI&lt;/a&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6uykg9u3hhpxh68zfeu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6uykg9u3hhpxh68zfeu.png" alt="FastAPI Swagger UI"&gt;&lt;/a&gt;&lt;br&gt;
The docs are available at this link: {host}:{port}/docs&lt;/p&gt;

&lt;p&gt;After that: Have fun :)&lt;/p&gt;

&lt;p&gt;For more details, please read the &lt;a href="https://github.com/manukanne/cloudatlas-quiz-api/blob/main/README.md" rel="noopener noreferrer"&gt;README.md&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Submission Category: Choose Your Own Adventure
&lt;/h3&gt;
&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/manukanne" rel="noopener noreferrer"&gt;
        manukanne
      &lt;/a&gt; / &lt;a href="https://github.com/manukanne/cloudatlas-quiz-api" rel="noopener noreferrer"&gt;
        cloudatlas-quiz-api
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;MongoDB Quiz API&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This project was created as part of the MongoDB Hackathon, it is a quiz API that provides the following functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authentication/ Authorization using OAuth2&lt;/li&gt;
&lt;li&gt;CRUD Operations for quiz categories&lt;/li&gt;
&lt;li&gt;CRUD Operations for quizzes
&lt;ul&gt;
&lt;li&gt;Including Quiz submition and calulating the total and reached points&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Also, the project is fully covered by unit tests&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This project is built on top of the Python FastApi framework using the awesome cloud based MongoDB Atlas database.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Dependencies&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Tech-stack&lt;/h4&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Python 3.9&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fastapi.tiangolo.com/" rel="nofollow noopener noreferrer"&gt;FastApi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/cloud/atlas" rel="nofollow noopener noreferrer"&gt;MongoDB Cloud Atlas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.mongoengine.org/index.html" rel="nofollow noopener noreferrer"&gt;MongoEngine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installing&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;1. Clone the git repo:&lt;/h4&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;git clone https://github.com/manukanne/cloudatlas-quiz-api.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;2. Download and install Python&lt;/h4&gt;

&lt;/div&gt;
&lt;p&gt;To download python, please vistit this &lt;a href="https://www.python.org/downloads/" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For this project the following Python version was used: 3.9.*&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;3. Create a python virtual envrionment:&lt;/h4&gt;

&lt;/div&gt;
&lt;p&gt;For more information on how to create please visit this &lt;a href="https://docs.python.org/3.9/library/venv.html" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;4. Install the required packages&lt;/h4&gt;

&lt;/div&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;pip install requirement.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For more information, please vist this &lt;a href="https://pip.pypa.io/en/stable/cli/pip_install/" rel="nofollow noopener noreferrer"&gt;link&lt;/a&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/manukanne/cloudatlas-quiz-api" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/" rel="noopener noreferrer"&gt;Architecture Patterns with Python&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>atlashackathon</category>
      <category>python</category>
      <category>mongodb</category>
    </item>
  </channel>
</rss>
