Skip to content

Commit d117268

Browse files
authored
Merge pull request #555 from VariantEffect/maintenance/bencap/542/cleanup-open-api-docs
Clean and Standardize OpenAPI Documentation
2 parents 7b4a20c + 01e3db1 commit d117268

36 files changed

+1210
-436
lines changed

src/mavedb/lib/authorization.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from typing import Optional
33

44
from fastapi import Depends, HTTPException
5-
from starlette import status
65

76
from mavedb.lib.authentication import UserData, get_current_user
87
from mavedb.lib.logging.context import logging_context, save_to_logging_context
@@ -21,10 +20,7 @@ async def require_current_user(
2120
) -> UserData:
2221
if user_data is None:
2322
logger.info(msg="Non-authenticated user attempted to access protected route.", extra=logging_context())
24-
raise HTTPException(
25-
status_code=status.HTTP_401_UNAUTHORIZED,
26-
detail="Could not validate credentials",
27-
)
23+
raise HTTPException(status_code=401, detail="Could not validate credentials")
2824

2925
return user_data
3026

@@ -38,8 +34,7 @@ async def require_current_user_with_email(
3834
msg="User attempted to access email protected route without a valid email.", extra=logging_context()
3935
)
4036
raise HTTPException(
41-
status_code=status.HTTP_400_BAD_REQUEST,
42-
detail="There must be an email address associated with your account to use this feature.",
37+
status_code=403, detail="There must be an email address associated with your account to use this feature."
4338
)
4439
return user_data
4540

@@ -54,10 +49,7 @@ async def __call__(self, user_data: UserData = Depends(require_current_user)) ->
5449
logger.info(
5550
msg="User attempted to access role protected route without a required role.", extra=logging_context()
5651
)
57-
raise HTTPException(
58-
status_code=status.HTTP_401_UNAUTHORIZED,
59-
detail="You are not authorized to use this feature",
60-
)
52+
raise HTTPException(status_code=403, detail="You are not authorized to use this feature")
6153

6254
return user_data
6355

@@ -68,9 +60,6 @@ async def require_role(roles: list[UserRole], user_data: UserData = Depends(requ
6860
logger.info(
6961
msg="User attempted to access role protected route without a required role.", extra=logging_context()
7062
)
71-
raise HTTPException(
72-
status_code=status.HTTP_401_UNAUTHORIZED,
73-
detail="You are not authorized to use this feature",
74-
)
63+
raise HTTPException(status_code=403, detail="You are not authorized to use this feature")
7564

7665
return user_data

src/mavedb/lib/taxonomies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ async def search_NCBI_taxonomy(db: Session, search: str) -> Any:
6666
else:
6767
raise HTTPException(status_code=404, detail=f"Taxonomy with search {search_text} not found in NCBI")
6868
else:
69-
raise HTTPException(status_code=404, detail="Please enter valid searching words")
69+
raise HTTPException(status_code=400, detail="Search text is required")
7070

7171
return taxonomy_record

src/mavedb/routers/access_keys.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from fastapi import APIRouter, Depends
99
from fastapi.encoders import jsonable_encoder
1010
from fastapi.exceptions import HTTPException
11+
from sqlalchemy import and_
1112
from sqlalchemy.orm import Session
1213

1314
from mavedb import deps
@@ -17,15 +18,27 @@
1718
from mavedb.lib.logging.context import logging_context, save_to_logging_context
1819
from mavedb.models.access_key import AccessKey
1920
from mavedb.models.enums.user_role import UserRole
21+
from mavedb.routers.shared import ACCESS_CONTROL_ERROR_RESPONSES, PUBLIC_ERROR_RESPONSES, ROUTER_BASE_PREFIX
2022
from mavedb.view_models import access_key
2123

24+
TAG_NAME = "Access Keys"
25+
2226
router = APIRouter(
23-
prefix="/api/v1",
24-
tags=["access keys"],
25-
responses={404: {"description": "Not found"}},
27+
prefix=f"{ROUTER_BASE_PREFIX}",
28+
tags=[TAG_NAME],
29+
responses={**PUBLIC_ERROR_RESPONSES},
2630
route_class=LoggedRoute,
2731
)
2832

33+
metadata = {
34+
"name": TAG_NAME,
35+
"description": "Manage API access keys for programmatic access to the MaveDB API.",
36+
"externalDocs": {
37+
"description": "Access Keys Documentation",
38+
"url": "https://mavedb.org/docs/mavedb/accounts.html#api-access-tokens",
39+
},
40+
}
41+
2942
logger = logging.getLogger(__name__)
3043

3144

@@ -49,7 +62,8 @@ def generate_key_pair():
4962
"/users/me/access-keys",
5063
status_code=200,
5164
response_model=list[access_key.AccessKey],
52-
responses={404: {}, 500: {}},
65+
responses={**ACCESS_CONTROL_ERROR_RESPONSES},
66+
summary="List my access keys",
5367
)
5468
def list_my_access_keys(*, user_data: UserData = Depends(require_current_user)) -> Any:
5569
"""
@@ -62,7 +76,8 @@ def list_my_access_keys(*, user_data: UserData = Depends(require_current_user))
6276
"/users/me/access-keys",
6377
status_code=200,
6478
response_model=access_key.NewAccessKey,
65-
responses={404: {}, 500: {}},
79+
responses={**ACCESS_CONTROL_ERROR_RESPONSES},
80+
summary="Create a new access key for myself",
6681
)
6782
def create_my_access_key(
6883
*,
@@ -88,7 +103,8 @@ def create_my_access_key(
88103
"/users/me/access-keys/{role}",
89104
status_code=200,
90105
response_model=access_key.NewAccessKey,
91-
responses={404: {}, 500: {}},
106+
responses={**ACCESS_CONTROL_ERROR_RESPONSES},
107+
summary="Create a new access key for myself with a specified role",
92108
)
93109
async def create_my_access_key_with_role(
94110
*,
@@ -125,7 +141,12 @@ async def create_my_access_key_with_role(
125141
return response_item
126142

127143

128-
@router.delete("/users/me/access-keys/{key_id}", status_code=200, responses={404: {}, 500: {}})
144+
@router.delete(
145+
"/users/me/access-keys/{key_id}",
146+
status_code=200,
147+
responses={**ACCESS_CONTROL_ERROR_RESPONSES},
148+
summary="Delete one of my access keys",
149+
)
129150
def delete_my_access_key(
130151
*,
131152
key_id: str,
@@ -135,8 +156,20 @@ def delete_my_access_key(
135156
"""
136157
Delete one of the current user's access keys.
137158
"""
138-
item = db.query(AccessKey).filter(AccessKey.key_id == key_id).one_or_none()
139-
if item and item.user.id == user_data.user.id:
140-
db.delete(item)
141-
db.commit()
142-
logger.debug(msg="Successfully deleted provided API key.", extra=logging_context())
159+
item = (
160+
db.query(AccessKey)
161+
.filter(and_(AccessKey.key_id == key_id, AccessKey.user_id == user_data.user.id))
162+
.one_or_none()
163+
)
164+
165+
if not item:
166+
logger.warning(
167+
msg="Could not delete API key; Provided key ID does not exist and/or does not belong to the current user.",
168+
extra=logging_context(),
169+
)
170+
# Never acknowledge the existence of an access key that doesn't belong to the user.
171+
raise HTTPException(status_code=404, detail=f"Access key with ID {key_id} not found.")
172+
173+
db.delete(item)
174+
db.commit()
175+
logger.debug(msg="Successfully deleted provided API key.", extra=logging_context())

src/mavedb/routers/api_information.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,27 @@
33
from fastapi import APIRouter
44

55
from mavedb import __project__, __version__
6+
from mavedb.routers.shared import PUBLIC_ERROR_RESPONSES, ROUTER_BASE_PREFIX
67
from mavedb.view_models import api_version
78

8-
router = APIRouter(prefix="/api/v1/api", tags=["api information"], responses={404: {"description": "Not found"}})
9+
TAG_NAME = "API Information"
910

11+
router = APIRouter(
12+
prefix=f"{ROUTER_BASE_PREFIX}/api",
13+
tags=[TAG_NAME],
14+
responses={**PUBLIC_ERROR_RESPONSES},
15+
)
1016

11-
@router.get("/version", status_code=200, response_model=api_version.ApiVersion, responses={404: {}})
17+
metadata = {
18+
"name": TAG_NAME,
19+
"description": "Retrieve information about the MaveDB API.",
20+
}
21+
22+
23+
@router.get("/version", status_code=200, response_model=api_version.ApiVersion, summary="Show API version")
1224
def show_version() -> Any:
1325
"""
14-
Describe the API version.
26+
Describe the API version and project.
1527
"""
1628

1729
return api_version.ApiVersion(name=__project__, version=__version__)

0 commit comments

Comments
 (0)