A regular folder works on one computer. After deployment it is unreliable: a
container can be replaced, and several application instances do not share one local
disk. Object storage solves this problem.
S3 stores files as objects inside a bucket. The application identifies one by
its key. A key may look like covers/uuid.webp, but it is not a local filesystem
path. The bucket says โwhich collectionโ; the key says โwhich objectโ.
Store these separately:
keyโ the stable identifier used for reading and deletion;- URL โ an access mechanism that may be temporary;
- metadata โ size, detected type, and owner.
Do not parse a key back out of a URL; domains, encoding, and signatures can change.
One file’s journey
- The application validates the upload.
- The server generates an unpredictable key.
- A storage adapter saves the bytes.
- The database stores the key and metadata, not a temporary URL signature.
- The app builds a URL for reading and uses the saved key for deletion.
from typing import Protocol
class Storage(Protocol):
def save(self, key: str, data: bytes, content_type: str) -> str: ...
def delete(self, key: str) -> None: ...
One contract supports local storage in development and tests and S3 in production.
The FastAPI route should not know boto3 details.
This lets a learning project work locally without cloud credentials. Connecting S3
later does not require rewriting the routes.
Generate unpredictable server-side keys, grant only required IAM actions, never
commit credentials, set the correct ContentType, and avoid making a whole bucket
public for one file. Use short-lived presigned URLs for private access. A presigned
URL is temporary access, not a stable database identifier or a replacement for app
authorization. The user authenticates in your application first; only then does the
server decide whether to issue a link. Expiring a presigned URL does not delete the
objectโit only ends access through that signature.
๐ฌ Comments (0)
No comments yet
Be the first to share your opinion about this article!