Skip to content

Commit

Permalink
Merge pull request #23 from TheJacksonLaboratory/GW-152-publication-api
Browse files Browse the repository at this point in the history
Gw 152 publication api
  • Loading branch information
francastell authored Feb 6, 2024
2 parents 9b279ad + e7b8dd5 commit 66bbbbd
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 5 deletions.
4 changes: 2 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "geneweaver-api"
version = "0.2.0a0"
version = "0.2.0a1"
description = "description"
authors = ["Jax Computational Sciences <cssc@jax.org>"]
packages = [
Expand Down
3 changes: 2 additions & 1 deletion src/geneweaver/api/controller/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""
from fastapi import APIRouter, FastAPI, Security
from geneweaver.api import __version__
from geneweaver.api.controller import genes, genesets
from geneweaver.api.controller import genes, genesets, publications
from geneweaver.api.core import deps
from geneweaver.api.core.config import settings

Expand All @@ -26,5 +26,6 @@
)
api_router.include_router(genesets.router)
api_router.include_router(genes.router)
api_router.include_router(publications.router)

app.include_router(api_router, prefix=settings.API_PREFIX)
1 change: 1 addition & 0 deletions src/geneweaver/api/controller/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
ACCESS_FORBIDDEN = "Forbidden"
UNEXPECTED_ERROR = "Unexpected Error"
GENE_IDENTIFIER_TYPE_VALUE_ERROR = "Invalid gene identifier type"
RECORD_NOT_FOUND_ERROR = "Record not found"
40 changes: 40 additions & 0 deletions src/geneweaver/api/controller/publications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Endpoints related to publications."""
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Path
from geneweaver.api import dependencies as deps
from geneweaver.api.services import publications as publication_service
from typing_extensions import Annotated

from . import message as api_message

router = APIRouter(prefix="/publications", tags=["publications"])


@router.get("/{pub_id}")
def get_publication_by_id(
pub_id: Annotated[
int, Path(format="int64", minimum=0, maxiumum=9223372036854775807)
],
cursor: Optional[deps.Cursor] = Depends(deps.cursor),
) -> dict:
"""Get a publication by id."""
response = publication_service.get_publication(cursor, pub_id)

if response.get("publication") is None:
raise HTTPException(status_code=404, detail=api_message.RECORD_NOT_FOUND_ERROR)

return response


@router.get("/pubmed/{pubmed_id}")
def get_publication_by_pubmed_id(
pubmed_id: str, cursor: Optional[deps.Cursor] = Depends(deps.cursor)
) -> dict:
"""Get a publication by id."""
response = publication_service.get_publication_by_pubmed_id(cursor, pubmed_id)

if response.get("publication") is None:
raise HTTPException(status_code=404, detail=api_message.RECORD_NOT_FOUND_ERROR)

return response
37 changes: 37 additions & 0 deletions src/geneweaver/api/services/publications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Service functions for publications."""

from fastapi.logger import logger
from geneweaver.db import publication as db_publication
from psycopg import Cursor


def get_publication(cursor: Cursor, pub_id: int) -> dict:
"""Get a publication by ID from the DB.
@param cursor: DB cursor
@param pub_id: publication identifier
@return: dictionary response (publication).
"""
try:
pub = db_publication.by_id(cursor, pub_id)
return {"publication": pub}

except Exception as err:
logger.error(err)
raise err


def get_publication_by_pubmed_id(cursor: Cursor, pub_med_id: str) -> dict:
"""Get a publication by Pubmed Id from the DB.
@param cursor: DB cursor
@param pub_med_id: pub med identifier
@return: dictionary response (publication).
"""
try:
pub = db_publication.by_pubmed_id(cursor, pub_med_id)
return {"publication": pub}

except Exception as err:
logger.error(err)
raise err
2 changes: 1 addition & 1 deletion tests/controllers/test_genesets.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,5 @@ def test_invalid_gene_type_id(mock_service_get_geneset_w_gene_id_type, client):
mock_service_get_geneset_w_gene_id_type.return_value = geneset_w_gene_id_type_resp
response = client.get("/api/genesets/1234/file?gene_id_type=25")

assert 'ctx' in response.json()["detail"][0]
assert "ctx" in response.json()["detail"][0]
assert response.status_code == 422
62 changes: 62 additions & 0 deletions tests/controllers/test_publications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Tests for geneset API."""
from unittest.mock import patch

from geneweaver.api.controller import message

from tests.data import test_publication_data

publication_by_id_resp = test_publication_data.get("publication_by_id")
publication_by_pubmed_id_resp = test_publication_data.get("publication_by_pubmed_id")


@patch("geneweaver.api.services.publications.get_publication")
def test_valid_url_req(mock_pub_service_call, client):
"""Test valid url request to get publication by id."""
mock_pub_service_call.return_value = publication_by_id_resp

response = client.get(url="/api/publications/123")

assert response.status_code == 200
assert response.json() == publication_by_id_resp


@patch("geneweaver.api.services.publications.get_publication_by_pubmed_id")
def test_valid_pubmed_url_req(mock_pub_service_call, client):
"""Test valid url request to get publication by pubmed id."""
mock_pub_service_call.return_value = publication_by_pubmed_id_resp

response = client.get(url="/api/publications/pubmed/17931734")

assert response.status_code == 200
assert response.json() == publication_by_pubmed_id_resp


@patch("geneweaver.api.services.publications.get_publication")
def test_pub_record_not_found(mock_pub_service_call, client):
"""Test pub record not found response."""
mock_pub_service_call.return_value = {"publication": None}

response = client.get(url="/api/publications/456456")

assert response.status_code == 404
assert response.json() == {"detail": message.RECORD_NOT_FOUND_ERROR}


@patch("geneweaver.api.services.publications.get_publication_by_pubmed_id")
def test_pubmed_record_not_found(mock_pub_service_call, client):
"""Test pubmed record not found response."""
mock_pub_service_call.return_value = {"publication": None}

response = client.get(url="/api/publications/pubmed/456456")

assert response.status_code == 404
assert response.json() == {"detail": message.RECORD_NOT_FOUND_ERROR}


@patch("geneweaver.api.services.publications.get_publication")
def test_invalid_pub_id_type(mock_pub_service_call, client):
"""Test pub record not found response."""
mock_pub_service_call.return_value = {"publication": None}

response = client.get(url="/api/publications/werte123")
assert response.status_code == 422
10 changes: 10 additions & 0 deletions tests/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"tests.data", "homologus_ids.json"
)

publications_json = importlib.resources.read_text("tests.data", "publications.json")

## laod and returns JSON string as a dictionary

# geneset test data
Expand Down Expand Up @@ -45,3 +47,11 @@
"gene_ids_map_resp_3"
),
}

# publication test data
test_publication_data = {
"publication_by_id": json.loads(publications_json).get("publication_by_id"),
"publication_by_pubmed_id": json.loads(publications_json).get(
"publication_by_pubmed_id"
),
}
30 changes: 30 additions & 0 deletions tests/data/publications.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"publication_by_id": {
"publication": {
"id": 123,
"authors": "Tabakoff B, Bhave SV, Hoffman PL",
"title": "Selective breeding, quantitative trait locus analysis, and gene arrays identify candidate genes for complex drug-related behaviors.",
"abstract": "Acute functional tolerance to ethanol develops during a single exposure to ethanol; it has been suggested to be a predisposing factor for the development of ethanol dependence. Genetic determinants of acute functional tolerance, as well as of ethanol dependence, have been clearly demonstrated. We describe a novel approach that uses a combination of selective breeding (to segregate genes contributing to the phenotype of interest, i.e., acute functional tolerance to the incoordinating effect of ethanol), quantitative trait locus analysis (to define chromosomal regions associated with acute functional tolerance), and DNA microarray technology (to identify differentially expressed genes in the brains of the selected lines of mice) to identify candidate genes for the complex phenotype of ethanol tolerance. The results indicate the importance of a signal transduction cascade that involves the glutamate receptor delta2 protein, the Ephrin B3 ligand, and the NMDA receptor, as well as a transcriptional regulatory protein that may be induced by activation of the NMDA receptor (zinc finger protein 179) and a protein that can modulate downstream responses to NMDA receptor activation (peroxiredoxin), in mediating acute tolerance to the incoordinating effect of ethanol.",
"journal": "The Journal of neuroscience : the official journal of the Society for Neuroscience",
"volume": "23",
"pages": "4491-8",
"month": "Jun",
"year": "2003",
"pubmed_id": "12805289"
}
},
"publication_by_pubmed_id": {
"publication": {
"id": 1234,
"authors": "Kovacs P, Kress R, Rocha J, Kurtz U, Miquel JF, Nervi F, Mndez-Snchez N, Uribe M, Bock HH, Schirin-Sokhan R, Stumvoll M, Mssner J, Lammert F, Wittenburg H",
"title": "Variation of the gene encoding the nuclear bile salt receptor FXR and gallstone susceptibility in mice and humans.",
"abstract": "From quantitative trait locus mapping in inbred mice, we identified the Nr1h4 gene encoding the nuclear bile salt receptor FXR as a candidate gene for the cholesterol gallstone susceptibility locus Lith7. Here, we investigated further an association of the gene encoding FXR and gallstone susceptibility in mice and humans.The Nr1h4 gene was sequenced in inbred mouse strains with susceptible and resistant Lith7 alleles. Quantitative RT-PCR was employed to determine mRNA expression levels. Gallstone carriers and control subjects of three different populations comprising 1004 individuals were genotyped for polymorphisms of the orthologous human gene detected by sequencing.Expression and sequence analyses in inbred mice were consistent with Nr1h4 underlying Lith7. In the human populations, we identified three frequent haplotypes that accounted for &gt; 95% of all haplotypes observed. In a Mexican population, the most common haplotype NR1H4_1 was associated with gallstone prevalence. In contrast, NR1H4_1 displayed no association with gallstone prevalence in a German population, whereas in a Chilean population we observed a trend towards a protective effect of NR1H4_1.Our study in an inbred mouse model and in three ethnically distinct populations indicates complex interactions of NR1H4 alleles and other risk factors for the development of cholelithiasis.",
"journal": "Journal of hepatology",
"volume": "48",
"pages": "116-24",
"month": "Jan",
"year": "2008",
"pubmed_id": "17931734"
}
}
}
30 changes: 30 additions & 0 deletions tests/services/test_publications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Tests for publications Service."""

from unittest.mock import patch

from geneweaver.api.services import publications as pub_service

from tests.data import test_publication_data

publication_by_id_resp = test_publication_data.get("publication_by_id")
publication_by_pubmed_id_resp = test_publication_data.get("publication_by_pubmed_id")


@patch("geneweaver.api.services.publications.db_publication")
def test_get_publication_by_id(mock_db_publication):
"""Test get publication by ID data response structure."""
mock_db_publication.by_id.return_value = publication_by_id_resp

response = pub_service.get_publication(None, 123)

assert response.get("publication") == publication_by_id_resp


@patch("geneweaver.api.services.publications.db_publication")
def test_get_publication_by_pubmed_id(mock_db_publication):
"""Test get publication by ID data response structure."""
mock_db_publication.by_pubmed_id.return_value = publication_by_id_resp

response = pub_service.get_publication_by_pubmed_id(None, "17931734")

assert response.get("publication") == publication_by_id_resp

0 comments on commit 66bbbbd

Please sign in to comment.