diff --git a/azure/functions/_http_asgi.py b/azure/functions/_http_asgi.py index 879a37e6..4273c03e 100644 --- a/azure/functions/_http_asgi.py +++ b/azure/functions/_http_asgi.py @@ -4,6 +4,7 @@ from typing import Dict, List, Tuple, Optional, Any, Union import logging import asyncio +from warnings import warn from wsgiref.headers import Headers from ._abc import Context @@ -149,18 +150,20 @@ def __init__(self, app): self.main = self._handle def handle(self, req: HttpRequest, context: Optional[Context] = None): - """Method to convert an Azure Functions HTTP request into a ASGI - Python object. Example on handling ASGI app in a HTTP trigger by - calling .handle() in .main() method: + """Deprecated. Please use handle_async instead: import azure.functions as func from FastapiApp import app - def main(req, context): - return func.AsgiMiddleware(app).handle(req, context) + async def main(req, context): + return await func.AsgiMiddleware(app).handle_async(req, context) """ + warn("handle() is deprecated. Please use handle_async() instead.", + DeprecationWarning, stacklevel=2) self._logger.debug(f"Handling {req.url} as an ASGI request.") + self._logger.warning( + "handle() is deprecated. Please `await .handle_async()` instead.") return self._handle(req, context) def _handle(self, req, context): @@ -172,3 +175,29 @@ def _handle(self, req, context): ) return asgi_response.to_func_response() + + async def handle_async(self, + req: HttpRequest, + context: Optional[Context] = None): + """Method to convert an Azure Functions HTTP request into a ASGI + Python object. Example on handling ASGI app in a HTTP trigger by + calling .handle_async() in .main() method: + + import azure.functions as func + + from FastapiApp import app + + async def main(req, context): + return await func.AsgiMiddleware(app).handle_async(req, + context) + """ + self._logger.debug(f"Awaiting {req.url} as an ASGI request.") + return await self._handle_async(req, context) + + async def _handle_async(self, req, context): + asgi_request = AsgiRequest(req, context) + scope = asgi_request.to_asgi_http_scope() + asgi_response = await AsgiResponse.from_app(self._app, + scope, + req.get_body()) + return asgi_response.to_func_response() diff --git a/tests/test_http_asgi.py b/tests/test_http_asgi.py index e48d541c..4395fd72 100644 --- a/tests/test_http_asgi.py +++ b/tests/test_http_asgi.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +import asyncio import unittest import azure.functions as func @@ -194,3 +195,22 @@ def test_middleware_wrapper(self): # Verify asserted self.assertEqual(response.status_code, 200) self.assertEqual(response.get_body(), test_body) + + def test_middleware_async_calls_app_with_context(self): + """Test the middleware with the awaitable handle_async() method + async def main(req, context): + return await AsgiMiddleware(app).handle_async(req, context) + """ + app = MockAsgiApplication() + test_body = b'Hello world!' + app.response_body = test_body + app.response_code = 200 + req = self._generate_func_request() + ctx = self._generate_func_context() + response = asyncio.get_event_loop().run_until_complete( + AsgiMiddleware(app).handle_async(req, ctx) + ) + + # Verify asserted + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get_body(), test_body)