Skip to content

Commit

Permalink
Add in fast api versionizer
Browse files Browse the repository at this point in the history
  • Loading branch information
TawneeOwl committed Dec 24, 2024
1 parent ed8d89e commit d48266f
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 24 deletions.
8 changes: 8 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
from fastapi import FastAPI
from .routers import case_information, security
from .config.docs import config as docs_config
from fastapi_versionizer.versionizer import Versionizer


def create_app() -> FastAPI:
app = FastAPI(**docs_config)
app.include_router(case_information.router)
app.include_router(security.router)

Versionizer(
app=app,
prefix_format="/v{major}",
semantic_version_format="{major}",
latest_prefix="/latest",
sort_routes=True,
).versionize()
return app
1 change: 0 additions & 1 deletion app/routers/case_information.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from app.auth.security import get_current_active_user
from app.models.users import UserScopes


logger = structlog.getLogger(__name__)


Expand Down
1 change: 0 additions & 1 deletion app/routers/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

from app.db import get_session


router = APIRouter(
responses={404: {"description": "Not found"}},
)
Expand Down
2 changes: 2 additions & 0 deletions requirements/generated/requirements-development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dnspython==2.7.0
email-validator==2.2.0
fastapi[standard]==0.115.2
fastapi-cli[standard]==0.0.5
fastapi-versionizer==4.0.1
filelock==3.15.4
freezegun==1.5.1
gitdb==4.0.11
Expand All @@ -37,6 +38,7 @@ mako==1.3.5
markdown-it-py==3.0.0
markupsafe==2.1.5
mdurl==0.1.2
natsort==8.4.0
nodeenv==1.9.1
packaging==24.1
passlib==1.7.4
Expand Down
2 changes: 2 additions & 0 deletions requirements/generated/requirements-production.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dnspython==2.7.0
email-validator==2.2.0
fastapi[standard]==0.115.2
fastapi-cli[standard]==0.0.5
fastapi-versionizer==4.0.1
greenlet==3.0.3
h11==0.14.0
httpcore==1.0.6
Expand All @@ -28,6 +29,7 @@ mako==1.3.5
markdown-it-py==3.0.0
markupsafe==2.1.5
mdurl==0.1.2
natsort==8.4.0
passlib==1.7.4
psycopg2-binary==2.9.9
pycparser==2.22
Expand Down
2 changes: 2 additions & 0 deletions requirements/generated/requirements-testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dnspython==2.7.0
email-validator==2.2.0
fastapi[standard]==0.115.2
fastapi-cli[standard]==0.0.5
fastapi-versionizer==4.0.1
freezegun==1.5.1
greenlet==3.0.3
h11==0.14.0
Expand All @@ -30,6 +31,7 @@ mako==1.3.5
markdown-it-py==3.0.0
markupsafe==2.1.5
mdurl==0.1.2
natsort==8.4.0
packaging==24.1
passlib==1.7.4
pluggy==1.5.0
Expand Down
1 change: 1 addition & 0 deletions requirements/source/requirements-base.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ argon2_cffi
structlog
typer
tabulate==0.9.0
fastapi-versionizer==4.0.1
24 changes: 14 additions & 10 deletions tests/auth/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@


def test_auth_fail_case(client: TestClient):
response = client.post("/cases/", json={"category": "Housing", "name": "John Doe"})
response = client.post(
"latest/cases/", json={"category": "Housing", "name": "John Doe"}
)
json = response.json()
assert json["detail"] == "Not authenticated"
assert response.status_code == 401


def test_create_case_disabled_user(client: TestClient, auth_token_disabled_user):
response = client.get(
"/cases/", headers={"Authorization": f"Bearer {auth_token_disabled_user}"}
"latest/cases/", headers={"Authorization": f"Bearer {auth_token_disabled_user}"}
)
json = response.json()
assert json["detail"] == "User Disabled"
Expand All @@ -35,7 +37,7 @@ def test_create_case_disabled_user(client: TestClient, auth_token_disabled_user)

def test_username_token_fail(client: TestClient):
response = client.post(
"/token",
"latest/token",
data={"username": "fake_user", "password": "incorrect"},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
Expand All @@ -46,7 +48,7 @@ def test_username_token_fail(client: TestClient):

def test_raw_token_fail(client: TestClient):
response = client.post(
"/token",
"latest/token",
data={"username": "cla_admin", "password": "cla_admin"},
headers={"Content-Type": "raw"},
)
Expand All @@ -55,7 +57,7 @@ def test_raw_token_fail(client: TestClient):

def test_credential_exception(client: TestClient, auth_token):
response = client.get(
"/cases/", headers={"Authorization": f"Bearer {auth_token} + 1"}
"latest/cases/", headers={"Authorization": f"Bearer {auth_token} + 1"}
)
json = response.json()
assert json["detail"] == "Could not validate credentials"
Expand All @@ -67,7 +69,9 @@ def test_credential_exception_no_user(session, client: TestClient, auth_token):
user = session.get(User, username)
session.delete(user)
session.commit()
response = client.get("/cases/", headers={"Authorization": f"Bearer {auth_token}"})
response = client.get(
"latest/cases/", headers={"Authorization": f"Bearer {auth_token}"}
)
json = response.json()
assert json["detail"] == "Could not validate credentials"
assert response.status_code == 401
Expand Down Expand Up @@ -119,19 +123,19 @@ def test_token_defined_expiry():
def test_scopes_missing_scopes(client: TestClient, session: Session):
# Create the test user with no given scopes
# They should not be able to access the GET /cases resource as that requires the UserScopes.READ scope
assert_user_scope(session, client, [], "/cases", 401)
assert_user_scope(session, client, [], "latest/cases", 401)


def test_scopes_incorrect_scope(client: TestClient, session: Session):
# Create the test user with a UserScopes.CREATE scope
# They should not be able to access the GET /cases resource as that requires the UserScopes.READ scope
assert_user_scope(session, client, [UserScopes.CREATE], "/cases", 401)
assert_user_scope(session, client, [UserScopes.CREATE], "latest/cases", 401)


def test_scopes_correct_scope(client: TestClient, session: Session):
# Create the test user with a UserScopes.READ scope
# They should be able to access the GET /cases resource as that requires the UserScopes.READ scope
assert_user_scope(session, client, [UserScopes.READ], "/cases", 200)
assert_user_scope(session, client, [UserScopes.READ], "latest/cases", 200)


def assert_user_scope(
Expand All @@ -152,7 +156,7 @@ def assert_user_scope(

# Obtain an access token for the test user
response = client.post(
"/token",
"latest/token",
data={"username": username, "password": password},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
Expand Down
8 changes: 4 additions & 4 deletions tests/case_adaptations/test_case_adaptations.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_cascade_delete(session: Session):
def test_request_create_case_with_adaptations(client_authed: TestClient):
"""Test creating a case with adaptations through the api."""
case_data = get_case_test_data()
response = client_authed.post("/cases/", json=case_data)
response = client_authed.post("latest/cases/", json=case_data)
assert response.status_code == 201
assert_dicts_equal(
response.json()["case_adaptations"], case_data["case_adaptations"]
Expand All @@ -54,7 +54,7 @@ def test_request_update_case_with_adaptations(
session.commit()

adaptations_data = {"case_adaptations": get_case_test_data()["case_adaptations"]}
response = client_authed.put(f"/cases/{case.id}", json=adaptations_data)
response = client_authed.put(f"latest/cases/{case.id}", json=adaptations_data)
assert response.status_code == 200
assert_dicts_equal(
response.json()["case_adaptations"], adaptations_data["case_adaptations"]
Expand All @@ -66,7 +66,7 @@ def test_request_create_case_without_adaptations(client_authed: TestClient):
case_data = get_case_test_data()
del case_data["case_adaptations"]

response = client_authed.post("/cases/", json=case_data)
response = client_authed.post("latest/cases/", json=case_data)
assert response.status_code == 201
assert response.json()["case_adaptations"] is None

Expand All @@ -81,6 +81,6 @@ def test_request_update_case_without_adaptations(
case_data = get_case_test_data()
del case_data["case_adaptations"]

response = client_authed.put(f"/cases/{case.id}", json=case_data)
response = client_authed.put(f"latest/cases/{case.id}", json=case_data)
assert response.status_code == 200
assert response.json()["case_adaptations"] is None
12 changes: 6 additions & 6 deletions tests/cases/test_case_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@

def test_case_create_request(client_authed: TestClient, session: Session):
test_data = get_case_test_data()
response_json = client_authed.post("/cases", json=test_data).json()
response_json = client_authed.post("latest/cases", json=test_data).json()
assert_dicts_equal(response_json, test_data)


def test_case_create_request_minimal(client_authed: TestClient, session: Session):
"""Test the minimum data required to create a case."""
test_data = {"case_type": "Check if your client qualifies for legal aid"}
response_json = client_authed.post("/cases", json=test_data).json()
response_json = client_authed.post("latest/cases", json=test_data).json()

expected_data = {
**test_data,
Expand All @@ -40,7 +40,7 @@ def test_case_create_request_not_enough_data(
):
"""Test that we cannot create a without providing the minimum data required."""
test_data = {}
response = client_authed.post("/cases", json=test_data)
response = client_authed.post("latest/cases", json=test_data)
assert response.status_code == 422
assert response.reason_phrase == "Unprocessable Entity"

Expand Down Expand Up @@ -69,7 +69,7 @@ def test_case_update_request(client_authed: TestClient, session: Session):
],
}

response = client_authed.put(f"/cases/{original_case.id}", json=test_data)
response = client_authed.put(f"latest/cases/{original_case.id}", json=test_data)
updated_case = session.get(Case, original_case.id)
assert response.status_code == 200
assert updated_case.case_type == "Civil Legal Advice"
Expand Down Expand Up @@ -113,7 +113,7 @@ def test_case_update_existing_request(client_authed: TestClient, session: Sessio
],
}

response = client_authed.put(f"/cases/{original_case.id}", json=test_data)
response = client_authed.put(f"latest/cases/{original_case.id}", json=test_data)
updated_case = session.get(Case, original_case.id)
assert response.status_code == 200
assert updated_case.people[0].updated_at > original_updated_at
Expand All @@ -137,5 +137,5 @@ def test_case_update_invalid_id_request(client_authed: TestClient, session: Sess
],
}

response = client_authed.put(f"/cases/{case.id}", json=test_data)
response = client_authed.put(f"latest/cases/{case.id}", json=test_data)
assert response.status_code == 404
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def get_session_override():
def auth_token(client):
# Send POST request with x-www-form-urlencoded data
response = client.post(
"/token",
"latest/token",
data={"username": "cla_admin", "password": "cla_admin"},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
Expand All @@ -85,7 +85,7 @@ def client_authed(auth_token, client: TestClient, session: Session):
def auth_token_disabled_user(client):
# Send POST request with x-www-form-urlencoded data
response = client.post(
"/token",
"latest/token",
data={"username": "jane_doe", "password": "password"},
headers={"Content-Type": "application/x-www-form-urlencoded"},
)
Expand Down

0 comments on commit d48266f

Please sign in to comment.