Skip to content

Commit

Permalink
feat: Change API status code for nor found ACMG ratings (#388) (#419)
Browse files Browse the repository at this point in the history
  • Loading branch information
gromdimon authored Feb 2, 2024
1 parent 9229358 commit ab294cd
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 5 deletions.
20 changes: 17 additions & 3 deletions backend/app/api/api_v1/endpoints/acmgseqvar.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from fastapi import APIRouter, Depends, HTTPException
from typing import Annotated

from fastapi import APIRouter, Depends, Header, HTTPException, Response
from sqlalchemy.ext.asyncio import AsyncSession

from app import crud, schemas
Expand Down Expand Up @@ -90,6 +92,7 @@ async def get_acmgseqvar_by_user(
seqvar: str,
db: AsyncSession = Depends(deps.get_db),
user: User = Depends(current_active_user),
user_agent: Annotated[str | None, Header()] = None,
):
"""
Get a ACMG Sequence Variant by id.
Expand All @@ -98,10 +101,16 @@ async def get_acmgseqvar_by_user(
:type id: uuid
:return: ACMG Sequence Variant
:rtype: dict
:raises HTTPException 404: ACMG Sequence Variant not found
:note: If user_agent is browser, return 204 Response
"""
result = await crud.acmgseqvar.get_by_user(db, user_id=user.id, seqvar_name=seqvar)
if not result: # pragma: no cover
raise HTTPException(status_code=404, detail="ACMG Sequence Variant not found")
# if user_agent is browser, return 204, else 404
if user_agent and "Mozilla" in user_agent:
return Response(status_code=204)
else:
raise HTTPException(status_code=404, detail="ACMG Sequence Variant not found")
else:
return result

Expand Down Expand Up @@ -157,6 +166,7 @@ async def delete_acmgseqvar_by_user(
seqvar: str,
db: AsyncSession = Depends(deps.get_db),
user: User = Depends(current_active_user),
user_agent: Annotated[str | None, Header()] = None,
):
"""
Delete a ACMG Sequence Variant by id.
Expand All @@ -168,6 +178,10 @@ async def delete_acmgseqvar_by_user(
"""
result = await crud.acmgseqvar.get_by_user(db, user_id=user.id, seqvar_name=seqvar)
if not result: # pragma: no cover
raise HTTPException(status_code=404, detail="ACMG Sequence Variant not found")
# if user_agent is browser, return 204, else 404
if user_agent and "Mozilla" in user_agent:
return Response(status_code=204)
else:
raise HTTPException(status_code=404, detail="ACMG Sequence Variant not found")
else:
return await crud.acmgseqvar.remove(db, id=result.id)
42 changes: 42 additions & 0 deletions backend/tests/api/api_v1/test_acmgseqvar.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,10 +517,31 @@ async def test_get_no_acmgseqvar(
f"{settings.API_V1_STR}/acmgseqvar/get?seqvar=invalid",
)
# assert:
# Status code is 404 because we use internal agent
assert response.status_code == 404
assert response.json() == {"detail": "ACMG Sequence Variant not found"}


@pytest.mark.anyio
@pytest.mark.parametrize("test_user, client_user", [(SUPER, SUPER)], indirect=True)
async def test_get_no_acmgseqvar_with_browser_header(
db_session: AsyncSession,
client_user: TestClient,
test_user: User,
):
"""Test getting a acmgseqvar with no acmgseqvar by simulating the browser behaviour."""
_ = db_session
_ = test_user
# act:
response = client_user.get(
f"{settings.API_V1_STR}/acmgseqvar/get?seqvar=invalid",
headers={"user-agent": "Mozilla/5.0"},
)
# assert:
# Status code is 204 because we use browser header
assert response.status_code == 204


# ------------------------------------------------------------------------------
# /api/v1/acmgseqvar/update
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -895,5 +916,26 @@ async def test_delete_acmgseqvar_no_acmgseqvar(
f"{settings.API_V1_STR}/acmgseqvar/delete?seqvar=invalid",
)
# assert:
# Status code is 404 because we use internal agent
assert response.status_code == 404
assert response.json() == {"detail": "ACMG Sequence Variant not found"}


@pytest.mark.anyio
@pytest.mark.parametrize("test_user, client_user", [(SUPER, SUPER)], indirect=True)
async def test_delete_acmgseqvar_no_acmgseqvar_with_browser_header(
db_session: AsyncSession,
client_user: TestClient,
test_user: User,
):
"""Test deleting a acmgseqvar with invalid data by simulating the browser behaviour."""
_ = db_session
_ = test_user
# act:
response = client_user.delete(
f"{settings.API_V1_STR}/acmgseqvar/delete?seqvar=invalid",
headers={"user-agent": "Mozilla/5.0"},
)
# assert:
# Status code is 204 because we use browser header
assert response.status_code == 204
8 changes: 7 additions & 1 deletion frontend/src/api/acmgSeqvar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export class AcmgSeqVarClient {
mode: 'cors',
credentials: 'include'
})
if (response.status === 204) {
return null
}
return await response.json()
}

Expand Down Expand Up @@ -98,12 +101,15 @@ export class AcmgSeqVarClient {
/**
* Delete the ACMG rating for a variant.
*/
async deleteAcmgRating(seqVar: SeqvarImpl): Promise<AcmgRatingBackend> {
async deleteAcmgRating(seqVar: SeqvarImpl): Promise<AcmgRatingBackend | null> {
const response = await fetch(`${this.apiBaseUrl}acmgseqvar/delete?seqvar=${seqVar.toName()}`, {
method: 'DELETE',
mode: 'cors',
credentials: 'include'
})
if (response.status === 204) {
return null
}
return await response.json()
}
}
10 changes: 9 additions & 1 deletion frontend/src/stores/seqvarAcmgRating.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ export const useSeqvarAcmgRatingStore = defineStore('seqvarAcmgRating', () => {
}
const seqvarImpl = seqvarImplFromSeqvar(seqvar$)
const acmgRatingBackend = await acmgSeqvarClient.fetchAcmgRating(seqvarImpl)
if (acmgRatingBackend === null) {
return
}
if (acmgRatingBackend.acmg_rank?.criterias) {
acmgRatingStatus.value = true
// Go through the data and setPresense for each criteria
Expand Down Expand Up @@ -183,6 +186,9 @@ export const useSeqvarAcmgRatingStore = defineStore('seqvarAcmgRating', () => {
}
const seqvarImpl = seqvarImplFromSeqvar(seqvar$)
const acmgRatingBackend = await acmgSeqvarClient.fetchAcmgRating(seqvarImpl)
if (acmgRatingBackend === null) {
return
}
if (acmgRatingBackend.acmg_rank?.criterias) {
acmgRatingStatus.value = true
// Go through the data and setPresense for each criteria
Expand Down Expand Up @@ -241,7 +247,9 @@ export const useSeqvarAcmgRatingStore = defineStore('seqvarAcmgRating', () => {
try {
const acmgSeqvarClient = new AcmgSeqVarClient()
const acmgSeqvar = await acmgSeqvarClient.fetchAcmgRating(seqvarImpl)
if (
if (acmgSeqvar === null) {
await acmgSeqvarClient.saveAcmgRating(seqvarImpl, acmgRatingServer)
} else if (
acmgSeqvar &&
acmgSeqvar.detail !== 'ACMG Sequence Variant not found' &&
acmgSeqvar.detail !== 'Not Found'
Expand Down

0 comments on commit ab294cd

Please sign in to comment.