For a while, I’ve been using Python Azure Functions to power the Sharp Cooking Backend API. When I first created the API, the v2 programming model was still in preview and not fully ready. Now that it’s generally available, I finally upgraded. The v2 model reduces boilerplate code and adds features that weren’t previously possible—such as streaming responses, which is great for LLM models.

Here’s a quick overview of the process and what changed.

TL;DR

For the actual code changes, check out this SharpCooking PR.

1. Simplified Folder Structure

In v1, each function required its own folder and a function.json file. In v2, you can have multiple functions in the same folder, or even in a single file. Configuration is now handled with decorators instead of function.json files.

I decided to keep only the main function_app.py file in the API root and move all the functions into a functions folder. For easier navigation, I kept each function in its own file.

Before: V1 model

After: V2 model

2. Adjusting the Imports

To get the imports working again, I had to update all the files, including the unit tests. I also used this opportunity to rename all the main.py files to match the function names.

Example:

1
2
3
4
5
# From
from ..parse_recipe.main import main

# To
from ..functions.parse_recipe import parse_recipe

3. Using Blueprints to Register Multiple Functions

In v2, you can use blueprints to register multiple functions across different files or modules. Each function exposes a blueprint object where you define routes. In the main function file, typically function_app.py, you then import and register these blueprints.

In the function:

1
2
3
4
5
6
7
import azure.functions as func

bp = func.Blueprint()

@bp.route(route="parse-recipe", methods=["POST"]) 
def parse_recipe(req: func.HttpRequest) -> func.HttpResponse:
  # parse the recipe here

In the function_app.py file:

1
2
3
4
5
6
import azure.functions as func
from functions.parse_recipe import bp as parse_recipe_bp

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)

app.register_functions(parse_recipe_bp)

4. Updating Unit Tests

You can’t directly call the function in unit tests anymore; you need to use the Build() method to get the user function. This is explained in the Azure Functions documentation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import unittest
from ..functions.parse_recipe import parse_recipe

def test_recipe_parse():
  # prepare the request
  request = func.HttpRequest(
        method='POST',
        url='api/parse-recipe',
        body=json.dumps({
            'url': 'https://www.foodnetwork.com/recipes/rachael-ray/pork-chops-with-golden-apple-sauce-recipe-1915826',
        }).encode('utf8')
    )

    # you cannot call the function directly, you need to use the build()
    # method to get the user function
    func_call = parse_recipe.build().get_user_function()
    response = func_call(request)

    # assert response
    assert response.status_code == 200

Conclusion

The upgrade process was pretty straightforward, and I’m happy with the results. The code is cleaner and easier to navigate. I’m looking forward to leveraging streaming responses and other new features in v2 for future Sharp Cooking features.

Cheers,
Lucas