forked from microsoft/everyonecancode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
131 lines (105 loc) · 4.42 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
This is a simple FastAPI app developed for AnyoneCanCode that allows you to upload images to Azure Blob Storage.
This app is designed to be deployed to Azure App Service as a Linux container. It uses the Azure Storage SDK for Python to
stream images from Azure Blob Storage to the browser.
"""
import os
from datetime import datetime
from typing import List
from urllib.parse import quote
import uvicorn
from azure.core.exceptions import ResourceNotFoundError
from azure.storage.blob import BlobServiceClient
from fastapi import Depends, FastAPI, File, HTTPException, Request, UploadFile
from fastapi.responses import RedirectResponse, StreamingResponse, JSONResponse
from pydantic import BaseModel
app = FastAPI()
cache_header = {"Cache-Control": "max-age=31556952"}
shared_container_client = None
async def get_container_client():
"""Get a client to interact with the blob storage container."""
global shared_container_client
if not shared_container_client:
connection_string = os.environ["CUSTOMCONNSTR_STORAGE"]
service = BlobServiceClient.from_connection_string(conn_str=connection_string)
# Get a client to interact with a specific container - though it may not yet exist
shared_container_client = service.get_container_client("images")
return shared_container_client
@app.exception_handler(KeyError)
async def unicorn_exception_handler(request: Request, exc: KeyError):
"""Handle missing environment variables."""
if exc.args[0] == "CUSTOMCONNSTR_STORAGE":
return JSONResponse(
status_code=500,
content={
"message": f"Oops! You forgot to set the STORAGE connection string for your Azure Storage Account. You can test locally by setting CUSTOMCONNSTR_STORAGE. 🤓"
},
)
raise exc
@app.exception_handler(ValueError)
async def unicorn_exception_handler(request: Request, exc: KeyError):
if exc.args[0] == "Connection string is either blank or malformed.":
return JSONResponse(
status_code=500,
content={
"message": f"Oops! Your connection string is either blank or malformed. 🤓"
},
)
raise exc
class Image(BaseModel):
created_at: datetime = None
image_url: str
@app.get("/")
async def redirect_to_docs():
"""Redirect to the docs page."""
return RedirectResponse("/docs")
@app.get("/images", response_model=List[Image])
async def list_images(container_client=Depends(get_container_client)):
"""List all images from a blob storage container."""
try:
blobs = [
Image(created_at=b.last_modified, image_url=f"/images/{quote(b.name)}")
for b in container_client.list_blobs()
]
blobs.sort(key=lambda a: a.created_at, reverse=True)
except ResourceNotFoundError:
return JSONResponse(
status_code=500,
content={
"message": f"Oops! You forgot to create a blob storage container named 'images'. 🤓"
},
)
return blobs
@app.get("/images/{image_name}")
async def images(image_name, container_client=Depends(get_container_client)):
"""Stream an image from the blob storage container."""
try:
blob_container_client = container_client.get_blob_client(image_name)
blob = blob_container_client.download_blob()
except ResourceNotFoundError:
raise HTTPException(
status_code=404,
detail="Your picture was not found, just try to upload again. 🤓",
)
return StreamingResponse(blob.chunks(), headers=cache_header)
@app.delete("/images/{image_name}")
async def delete(image_name, container_client=Depends(get_container_client)):
"""Delete an image from the blob storage container."""
try:
blob_container_client = container_client.get_blob_client(image_name)
blob_container_client.delete_blob()
except ResourceNotFoundError:
raise HTTPException(status_code=404, detail="Your picture was not found. 🤓")
return {}
@app.post("/upload/")
async def upload(
file: UploadFile = File(...), container_client=Depends(get_container_client)
):
"""Upload an image to the blob storage container."""
container_client.upload_blob(
file.filename, file.file, blob_type="BlockBlob", overwrite=True
)
return {"filename": file.filename}
if __name__ == "__main__":
"""Run the app locally for testing."""
uvicorn.run(app, port=8000)