Routing in Azure Functions using python - python

I know that I can use query parameters in Azure functions to get the values
"myfunction?p=one&p2=two"
I am referring to this question
How can I do Routing in Azure Functions?
However it only addresses C# and node.js, I want to get the values following flask style
/function/<name>/<id>
which I can directly access, how do I do it in python in Azure functions
I also referred this doc, which only talks about node.js and C#
https://github.com/Azure/azure-functions-host/wiki/Http-Functions

You can add "route" to the function.json file to change the path, for example:
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"post"
],
"route": "contact/{version}/certificate"
}
....
]
And in file __init__.py,
you can get version by version = req.route_params.get('version')

To be more dynamic like the path type of Python Flask route in azure functions you can customize the route to be like below.
Main Concept is in the route's *{restOfPath}
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
],
"route": "Function1/{*restOfPath}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
and edit the host.json to remove the word api from the URL like below.
{
"http": {
"routePrefix": ""
}
}
so with above configuration you can have the Function to serve URLs like below
http://localhost:7071/Function1
http://localhost:7071/Function1/name
http://localhost:7071/Function1/name/id
http://localhost:7071/Function1/name/id/sub-name
http://localhost:7071/Function1/name/id/sub-name/sub-id
etc ...
Again to access it in init.py use it like below. You would get it as string
req.route_params.get("restOfPath")

It depends on if you are using Functions V1 or Functions V2. Note that neither is currently in General Availability: the Python language in V1 is considered experimental and will likely never go GA. The Python language worker for Functions V2 just went into private preview, and is currently in active development (see here). Overall, I highly recommend using Functions 2.0 for the best python support, and because it supports Python 3, while I believe that Functions V1 only supports Python 2.
With that said, the two versions both use the route parameter on the HTTP trigger function.json to configure the routes. To actually read the values, the two versions have very different approaches.
V1
You can set the custom route the same way you do for Node and C# in the function.json, by setting the "route" field of your HTTP Trigger binding. The route parameters are available as strings on the environment variables REQ_PARAMS_{route_param_name_as_upper_case}. So for your example, the route parameter values for name and id would be REQ_PARAMS_NAME and REQ_PARAMS_ID respectively.
V2
Again, you set the custom route in the function.json file the same way you do in all other languages. The route parameters are attached on the http request object as the property route_params, with the type of Mapping[str, str]
def main(req):
name = req.route_params.get('name')
return f'Hello, {name}!'

Related

Azure function app not triggering from an Event Hub

I have a event hub which is in Subscription A and a function app in Subscription B, i am trying to trigger the function app from the event hub in Subscription A, as per my research this should be possible and the correct connection string must be provided in the configuration of function app. I have done this but for some reason i am not able to trigger the function app.
Below is my function.json
{
"scriptFile": "__init__.py",
"bindings": [
{
"type": "eventHubTrigger",
"name": "event",
"direction": "in",
"eventHubName": "%eventHubName%",
"connection": "TestBench",
"cardinality": "one",
"consumerGroup": "$Default"
},
{
"type": "eventHub",
"name": "outputHub",
"direction": "out",
"connection": "outputConnection"
}
I have double checked the "TestBench" (eventhubs) connection string and also eventhub's name, they are correct.
Below is my function app code in __init__.py :
def main(event: func.EventHubEvent, outputHub: func.Out[List[str]]):
data=json.loads(event.get_body().decode('utf-8'))
logging.info(data)
Please verify if you have configured eventHubName property in the application setting of your function app as you have defined the binding as
"eventHubName": "%eventHubName%"
In case if this is correct then please validate whether the connection string is configured correctly or not.
I will suggest you to review the Diagnostic and solve problem blade on your function app that will help you diagnose the issue and the recommend solution to resolve your issue.
Please review the python example here and test the same at your end.

How to access Azure Service Bus using Function App identity

I am following the steps listed here, but for python code:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-identity-based-connections-tutorial-2
Objective is to create a simple (hello world) function app which is triggered by Azure Service Bus message queue using identity-based connection. Function app works fine when ASB is reference via connection string, but gives this error when trying to connect via managed service identity of function app (used the specific configuration pattern __fullyQualifiedNamespace). MSI has been granted Role (Azure Service Bus Data Receiver) on ASB.
Microsoft.Azure.WebJobs.ServiceBus: Microsoft Azure WebJobs SDK ServiceBus connection string 'ServiceBusConnection__fullyQualifiedNamespace' is missing or empty.
Function code (autogenerated)
import logging
import azure.functions as func
def main(msg: func.ServiceBusMessage):
logging.info('Python ServiceBus queue trigger processed message: %s',
msg.get_body().decode('utf-8'))
function.json (connection value modified based on ms docs)
{
"scriptFile": "__init__.py",
"bindings": [
{
"name": "msg",
"type": "serviceBusTrigger",
"direction": "in",
"queueName": "erpdemoqueue",
"connection": "ServiceBusConnection"
}
]
}
host.json (version modified based on ms docs)
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.3.0, 4.0.0)"
}
}
To use a managed identity, you'll need to add a setting that identifies the fully qualified namespace of your Service Bus instance.
For example, in your local.settings.json file for local development:
{
"Values": {
"<connection_name>__fullyQualifiedNamespace": "<service_bus_namespace>.servicebus.windows.net"
}
}
Or in the application settings for your function when deployed to Azure:
<connection_name>__fullyQualifiedNamespace=<service_bus_namespace>.servicebus.windows.net
This is mentioned only briefly in the tutorial that you linked. The Microsoft.Azure.WebJobs.Extensions.ServiceBus documentation does covers this a bit better in the Managed identity authentication section.

Azure Python Function: Underscore are not working in routes

Hello i am creating an "Azure Python Function" with an POST/GET route in the UNC path like http://localhost:7071/api/indicator/sjz_jb_1. I create therefore the following code :
function.json
In the previous version I used {indicator:alpa?} based on https://learn.microsoft.com/nl-nl/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=python#customize-the-http-endpoint. But with the alfa datatype the underscores are not working. After searching on the internet I found the stackoverflow post Underscore in URL not working with attribute routing it was based on c# but the code was still working but still result in a page not found.
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
],
"route": "indicator/{indicator:regex(^[a-zA-Z_]+$)}"
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
init.py
import logging
import json
import azure.functions as func
from shared_code.Metadata import Visualisatieportal_indicatoren
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
ind = req.route_params.get('indicator')
logging.info(ind)
indicator1 = Visualisatieportal_indicatoren.getVisualisatieportal_indicatoren(ind)
result = json.dumps(indicator1.__dict__)
return func.HttpResponse(str(id))
My question is, what do I need to change so the so underscores can support in the route of the endpoints.
Manny thanks
Erik
My question is, what do I need to change so the so underscores can
support in the route of the endpoints.
One of the workaround could solve the above issue,
To use underscore you can try with the below :
"route": "indicator/{indicator:regex(^[a-zA-Z0-9_]*$)}"
Also Based on this MS DOC we can not use following attribute in python function except c# & java.

Override the automatically generated parameters in FastAPI

I am writing FastAPI program that is just a bunch of #app.get endpoints for querying data. There are many, many different query arguments they could use that are automatically generated from a config file, for example the #app.get("/ADJUST_COLOR/") endpoint could look something like /ADJUST_COLOR/?RED_darker=10&BLUE_lighter=43&GREEN_inverse=true where all those parameters are generated from a list of colors and a list of operations to perform on those colors (This is only an example, not what I am actually doing).
The way I am doing that is to take in the request object like this:
#app.get("/ADJUST_COLOR/")
def query_COLORS( request: Request ):
return look_through_parameters(request.query_params)
But the problem is that the automatically generated swagger UI does not show any useful data:
Since I am parsing the request manually there are no parameters generated. But since I have a full list of the parameters I am expecting then I should be able to generate my own documentation and have the UI show it.
I have looked through these two documents: https://fastapi.tiangolo.com/tutorial/path-operation-configuration/
And https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/
But I was not able to figure out if it was possible or not
You can define custom api schema in your route via openapi_extra (this is a recent feature of FastAPI, 0.68 will work but I'm not sure the exact earliest version that supports this):
#app.get("/ADJUST_COLOR/", openapi_extra={
"parameters": [
{
"in": "query",
"name": "RED_darker",
"schema": {
"type": "integer"
},
"description": "The level of RED_darker"
},
{
"in": "query",
"name": "BLUE_lighter",
"schema": {
"type": "integer"
},
"description": "The level of BLUE_lighter"
},
{
"in": "query",
"name": "GREEN_inverse",
"schema": {
"type": "boolean"
},
"description": "is GREEN_inverse?"
},
]
})
async def query_COLORS(request: Request):
return look_through_parameters(request.query_params)
Which is rendered like this in your api /docs:

Azure Error: data protection system cannot create a new key because auto-generation of keys is disabled

I am trying to run an azure function on my local machine using Visual Studio Code.
My main.py looks like this:
import logging
import azure.functions as func
def main(event: func.EventHubEvent):
logging.info('Python EventHub trigger processed an event: %s', event.get_body().decode('utf-8'))
My host.json file looks like this:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
My function.json looks something like this:
{
"scriptFile": "main.py",
"bindings": [
{
"type": "eventHubTrigger",
"name": "event",
"direction": "in",
"eventHubName": "myhubName",
"connection": "myHubConnection",
"cardinality": "many",
"consumerGroup": "$Default"
}
]
}
The problem is when I run this, it throws me the following error:
A host error has occurred at
Microsoft.AspNetCore.DataProtection: An error occurred while trying to encrypt the provided data. Refer to the inner exception for more information. Microsoft.AspNetCore.DataProtection: The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled.
Value cannot be null.
Parameter name: provider
I am not sure what I am I missing ? Any help is appreciated
The problem was with the Azure Storage account:
Make sure the local.settings.json has the correct credentials for the storage account
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "MyStorageKey",
"FUNCTIONS_WORKER_RUNTIME": "python",
}
}

Categories