Writing an API with Flask#
Why Flask?
There's no set rule for developing APIs on Azure Functions. You can have one-function-one-api or integrate frameworks like Flask or FastAPI. We'll use Flask to enable easy migration of existing Flask apps.
Add Dependencies#
Update requirements.txt:
azure-functions
flask
flask-cors
flask-restful
pyjwt
werkzeug
azure-identity
azure-keyvault-secrets
opencensus-ext-azure
opencensus-ext-logging
opencensus-ext-flask
opencensus-ext-requests
opencensus-extension-azure-functions
Create Flask App#
Create the folder structure:
.
├── functiondemo/
│ ├── __init__.py
│ └── function.json
└── src/
└── api/
└── __init__.py
Flask App Code (src/api/__init__.py)#
import time
from flask import Flask, jsonify, request, Response, g
from flask_cors import CORS, cross_origin
import logging
app = Flask(__name__)
cors = CORS(origins='*', allow_headers=['Content-Type', 'Authorization'])
logger = logging.getLogger(__name__)
@app.before_request
def before_request():
g.start = time.time()
@app.after_request
def response_logger(response: Response):
response_time = round(time.time() - g.start, 3) * 1000
ip = request.headers.getlist("X-Forwarded-For")[0] if request.headers.getlist("X-Forwarded-For") else request.remote_addr
logger.info(f"addr={ip} method={request.method} url={request.url} response_time_ms={response_time}")
return response
@app.errorhandler(404)
def handle_not_found(ex):
return jsonify(message=f"Path {request.path} not found"), 404
@app.route("/health", methods=['GET', 'HEAD'])
def health():
return jsonify(message="Health Check Ok"), 200
@app.route("/vault", methods=['GET', 'HEAD'])
@cross_origin(cors)
def get_secret():
secret = request.args.get("secret")
return jsonify(message=f"Vault Integration not implemented for {secret}"), 200
Connect to Azure Function#
Update functiondemo/__init__.py:
import azure.functions as func
from src.api import app as application
def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
return func.WsgiMiddleware(application.wsgi_app).handle(req, context)
Configure Routing#
Update functiondemo/function.json:
{
"scriptFile": "__init__.py",
"bindings": [{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": ["get", "post", "head"],
"route": "{*route}"
}, {
"type": "http",
"direction": "out",
"name": "$return"
}]
}
Remove the /api prefix in host.json:
{
"extensions": {
"http": {
"routePrefix": ""
}
}
}
Test & Deploy#
# Test locally
http://localhost:7071/health
http://localhost:7071/vault?secret=demo
# Deploy
git push origin master