Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ETags #12

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions schoolsyst_api/etag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from hashlib import sha256
from typing import Callable

from fastapi.requests import Request
from fastapi_etag import Etag
from schoolsyst_api import database
from schoolsyst_api.models import OBJECT_KEY_FORMAT


def compute_for(collection_name: str) -> Callable[[Request], str]:
"""
Returns an `Etag` with a function that takes a Request and returns a SHA256
hexdigest hash of the `updated_at` field of an object from `collection_name`
with a _key equal to a path parameter `{key}`'s value as the etag generation function.
"""

async def compute(request: Request) -> str:
# Get the database
db = database.get()
# Get the key of the object from the path parameters from Request
key = request.path_params["key"]
# Get the collection name from the request path
collection_name = request.path.split("/")[1].replace("-", "_")
# Get the full key by getting the current user
# current_user_key = parse(auth.JWT_SUB_FORMAT, request.auth)
full_key = OBJECT_KEY_FORMAT.format(object=key, owner="current_user.key")
# Get the document from collection collection_name with _key key
document = db.collection(collection_name).get(full_key)
# Get the updated_at date
updated_at = document["updated_at"]
# Compute a hash of thet updated_at date
sha256hash = sha256(updated_at)
# Get the hexdigest of that hash (which is a `str`)
hexdigest = sha256hash.hexdigest()
return hexdigest

return Etag(compute)
3 changes: 3 additions & 0 deletions schoolsyst_api/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path

import fastapi_etag
import typed_dotenv
import uvicorn
from fastapi import FastAPI
Expand All @@ -20,6 +21,8 @@
typed_dotenv.load_into(EnvironmentVariables, Path(__file__).parent.parent / ".env")
# Initialize the database
api.add_event_handler("startup", database.initialize)
# Handle Etags
fastapi_etag.add_exception_handler(api)
# Handle CORS
api.add_middleware(**cors.middleware_params)
# Include routes
Expand Down
4 changes: 2 additions & 2 deletions schoolsyst_api/subjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from arango.database import StandardDatabase
from fastapi import Depends, HTTPException, Response, status
from fastapi_utils.inferring_router import InferringRouter
from schoolsyst_api import database
from schoolsyst_api import database, etag
from schoolsyst_api.accounts.users import get_current_confirmed_user
from schoolsyst_api.models import (
OBJECT_KEY_FORMAT,
Expand Down Expand Up @@ -67,7 +67,7 @@ def update_a_subject(
return db.collection("subjects").update(updated_subject, return_new=True)["new"]


@router.get("/subjects/{key}")
@router.get("/subjects/{key}", dependencies=[Depends(etag.compute_for("subjects"))])
def get_a_subject(
key: ObjectBareKey,
current_user: User = Depends(get_current_confirmed_user),
Expand Down