Notes for a future qh (and py2http perhaps).
#1
Replies: 2 comments
-
Dispatching a storeYes -- dispatching a function is the fundamental thing with which you can do all the rest. The problemI'd like to be able to wrap data access functionality into http services easily. On the backend I have an object that wraps a Mapping like this: from dataclasses import dataclass
from typing import MutableMapping
@dataclass
class StoreAccess:
"""
Delegator for MutableMapping, providing list, read, write, and delete methods.
This is intended to be used in web services, offering nicer method names than
the MutableMapping interface, and an actual list instead of a generator in
the case of list.
"""
store: MutableMapping
@classmethod
def from_uri(cls, uri: str):
"""code that makes a MutableMapping interface for the data pointed to by uri"""
def list(self):
return list(self.store.keys())
def read(self, key):
return self.store[key]
def write(self, key, value):
self.store[key] = value
def delete(self, key):
del self.store[key]I'd like to use FastAPI to make a webservice for this, which has four endpoints, one for each of the methods (list, read, write and delete). These should take the uri, as well as the other relevant arguments when relevant (key and/or value), and run those methods. Elements of a solutionTo create a web service with FastAPI that exposes the 1. Setup FastAPIFirst, ensure you have FastAPI and Uvicorn (an ASGI server) installed in your environment. If not, you can install them using pip: pip install fastapi uvicorn2. Define Your FastAPI AppCreate a new Python file for your FastAPI application, for example, from fastapi import FastAPI, HTTPException
from yourmodule import StoreAccess # Ensure this points to where your StoreAccess class is defined.
app = FastAPI()3. Create EndpointsYou'll define four endpoints corresponding to the methods in your List Endpoint@app.get("/list/{uri}")
async def list_keys(uri: str):
store = StoreAccess.from_uri(uri)
return store.list()Read Endpoint@app.get("/read/{uri}/{key}")
async def read_key(uri: str, key: str):
try:
store = StoreAccess.from_uri(uri)
return store.read(key)
except KeyError:
raise HTTPException(status_code=404, detail="Key not found")Write Endpoint@app.post("/write/{uri}")
async def write_key(uri: str, key: str, value: str): # Adjust value type based on your use case
store = StoreAccess.from_uri(uri)
store.write(key, value)
return {"message": "Value written successfully"}For the write endpoint, you might need to adjust how you accept the Delete Endpoint@app.delete("/delete/{uri}/{key}")
async def delete_key(uri: str, key: str):
try:
store = StoreAccess.from_uri(uri)
store.delete(key)
return {"message": "Key deleted successfully"}
except KeyError:
raise HTTPException(status_code=404, detail="Key not found")4. Run Your FastAPI AppYou can run your FastAPI app using Uvicorn. For example, if your FastAPI application is defined in uvicorn main:app --reloadThis command starts a local server on 5. Testing and DocumentationFastAPI automatically generates documentation for your API, accessible at Alternative Approaches and Considerations
By following these steps and considerations, you can create a robust web service with FastAPI that exposes your |
Beta Was this translation helpful? Give feedback.
-
getting the routes from the app objectWhen we test an So we could do this: def routes_of_app(app):
"""
Yields (name, func) pairs for the routes of azure.functions app.
(Note: Tested for `azure-functions==1.21.3`)
"""
for route in app._function_builders:
yield route._function._name, route._function._func
# example:
# dict(routes_of_app(app))That said, it's generally frowned upon to depend on non-public APIs. For a reason. We'd then have to maintain this routes_of_app function, and if it becomes hard, or impossible to retrieve the routes, we're in trouble. Another (considered more clean) possibility is to build our own "registration" mechanism, to accumulate the routes list/dict ourselves. registered_routes = {}
def register_route(route, methods):
def decorator(func):
# Register the function in your own registry.
registered_routes[route] = {
"methods": methods,
"handler": func,
}
return func
return decoratorWhich would be used like this: import azure.functions as af
app = FunctionApp(http_auth_level=af.AuthLevel.ANONYMOUS)
@app.route(route="foo", methods=["GET"])
@register_route("foo", ["GET"])
def foo(req: af.HttpRequest) -> af.HttpResponse:
...or to pack both decorators in one: import azure.functions as af
from azure.functions import FunctionApp
# Custom registry to keep track of routes and their handlers.
registered_routes = {}
def add_route(app: FunctionApp, route: str, methods: list, **kwargs):
"""
A decorator that registers a route handler with both the FunctionApp
and a custom registry.
Args:
app (FunctionApp): The Azure Functions app instance.
route (str): The route path.
methods (list): List of HTTP methods allowed (e.g., ["GET"] or ["GET", "POST"]).
**kwargs: Any additional keyword arguments to pass to app.route.
Returns:
A decorator that registers the function with both the custom registry and the app.
"""
def decorator(func_handler):
# Add the route to the custom registry.
registered_routes[route] = {
"methods": methods,
"handler": func_handler,
}
# Register the route using the standard app.route decorator.
return app.route(route=route, methods=methods, **kwargs)(func_handler)
return decoratorwhich could then be used like this: @add_route(app, route="foo", methods=["GET"])
def foo(req: func.HttpRequest) -> func.HttpResponse:
... |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
We're going to use
qh, which is not heavily used, as a place to develop a newpy2http(which is used more, but is getting fatigue). Here are some notes for this.Beta Was this translation helpful? Give feedback.
All reactions