Skip to content

Commit 67ea793

Browse files
committed
swagger complete
1 parent a0592e8 commit 67ea793

13 files changed

+311
-154
lines changed

DEPLOYING.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ Below are the steps to perform a production deployment of BioAPI.
3232
3333
BioAPI uses three genomic databases for its operation. These databases must be loaded in MongoDB. You can import all the databases in two ways:
3434
35-
3635
### Import using public DB backup (recommended)
3736
3837
To import all databases in MongoDB:
@@ -67,7 +66,6 @@ To import all databases in MongoDB:
6766
4. Stop services with the command `docker compose -f docker-compose.dev.yml down`
6867
5. Roll up the changes in the `docker-compose.dev.yml` file to remove the backup file from the `volumes` section. Restart all the services again.
6968
70-
7169
### Manually import the different databases
7270
7371
Alternatively (but **not recommended** due to high computational demands) you can run a separate ETL process to download from source, process and import the databases into MongoDB.
@@ -101,6 +99,7 @@ docker-compose up -d
10199
```
102100
103101
By default, BioAPI runs on `localhost:8000`.
102+
Test BioAPI with Swagger on `localhost:8000/apidocs`
104103
105104
If you want to stop all services, you can execute:
106105

bio-api/bioapi.py

+50-75
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
import logging
66

77
from flask import Flask, jsonify, make_response, abort, render_template, request
8-
# from apispec import APISpec
9-
# from apispec.ext.marshmallow import MarshmallowPlugin
10-
# from apispec_webframeworks.flask import FlaskPlugin
11-
# from flask_swagger_ui import get_swaggerui_blueprint
128
from flasgger import Swagger, swag_from
139
from db import get_mongo_connection
1410
from concurrent.futures import ThreadPoolExecutor
@@ -647,23 +643,10 @@ def associated_string_genes(gene_symbol: str, min_combined_score: int = 400) ->
647643
return res
648644

649645

650-
# Create an APISpec
651-
# spec = APISpec(
652-
# title="BioAPI",
653-
# version=VERSION,
654-
# openapi_version="2.0.0",
655-
# info=dict(
656-
# description="""
657-
# ## A powerful abstraction of genomics databases.
658-
# BioAPI is part of the Multiomix project. For more information, visit our [website](https://omicsdatascience.org/).
659-
# To contribute: [OmicsDatascience](https://github.com/omics-datascience/BioAPI)"""),
660-
# plugins=[FlaskPlugin()],
661-
# )
662-
663-
664646
def create_app():
665647
# Creates and configures the app
666648
flask_app = Flask(__name__, instance_relative_config=True)
649+
667650
swagger_config = {
668651
"headers": [
669652
],
@@ -672,8 +655,8 @@ def create_app():
672655
{
673656
"endpoint": "swagger",
674657
"route": "/apispec.json",
675-
"rule_filter": lambda rule: True, # all in
676-
"model_filter": lambda tag: True, # all in
658+
"rule_filter": lambda rule: True,
659+
"model_filter": lambda tag: True
677660
}
678661
],
679662
"title": "BioAPI",
@@ -726,8 +709,6 @@ def gene_symbols():
726709
return make_response(response, 200, headers)
727710

728711
@flask_app.route("/gene-symbols-finder/", methods=['GET'])
729-
# @doc(description='Gene symbols finder', tags=['Genes'])
730-
# @use_kwargs(args=swagger_schemas.GeneSymbolsFinderRequestSchema, location="query")
731712
@swag_from("swagger_specs/geneSymbolFinder.yml")
732713
def gene_symbol_finder():
733714
"""Takes a string of any length and returns a list of genes that contain that search criteria."""
@@ -751,8 +732,6 @@ def gene_symbol_finder():
751732
abort(400, e)
752733

753734
@flask_app.route("/information-of-genes", methods=['POST'])
754-
# @doc(description='Genes information', tags=['Genes'], consumes=["application/json"])
755-
# @use_kwargs(args=swagger_schemas.InformationOfGenesRequestSchema, location="json")
756735
@swag_from("swagger_specs/informationOfGenes.yml")
757736
def information_of_genes():
758737
"""Receives a list of gene IDs and returns information about them."""
@@ -771,7 +750,6 @@ def information_of_genes():
771750
return make_response(response, 200, headers)
772751

773752
@flask_app.route("/genes-of-its-group/<gene_id>", methods=['GET'])
774-
# @doc(description='Gene Groups', tags=['Genes'], params={"gene_id": {"description": "Identifier of the gene for any database", "type": "string", "required": True}})
775753
@swag_from("swagger_specs/genesOfItsGroup.yml")
776754
def genes_in_the_same_group(gene_id: str):
777755
response = {"gene_id": None, "groups": [],
@@ -809,9 +787,6 @@ def genes_in_the_same_group(gene_id: str):
809787

810788
@flask_app.route("/pathway-genes/<pathway_source>/<pathway_id>", methods=['GET'])
811789
@swag_from("swagger_specs/genesOfMetabolicPathway.yml")
812-
# @doc(description='Genes of a metabolic pathway', tags=['Genes'],
813-
# params={"pathway_source": {"description": "Database to query", "type": "string", "required": True, "example": "kegg", "enum": ["kegg", "biocarta", "ehmn", "humancyc", "inoh", "netpath", "pid", "reactome", "smpdb", "signalink", "wikipathways"]},
814-
# "pathway_id": {"description": "Pathway identifier in the source database", "type": "string", "required": True, "example": "hsa00740"}})
815790
def pathway_genes(pathway_source, pathway_id):
816791
if pathway_source.lower() not in PATHWAYS_SOURCES:
817792
abort(404, f'{pathway_source} is an invalid pathway source')
@@ -820,18 +795,17 @@ def pathway_genes(pathway_source, pathway_id):
820795
return make_response(response, 200, headers)
821796

822797
@flask_app.route("/pathways-in-common", methods=['POST'])
823-
# @doc(description='Metabolic pathways from different genes', tags=['Pathways'], consumes=["application/json"])
824-
# @use_kwargs(args=swagger_schemas.PathwaysInCommonRequestSchema, location="json")
825-
def pathways_in_common(gene_ids: List[str]):
826-
# body = request.get_json() # type: ignore
827-
# if "gene_ids" not in body:
828-
# abort(400, "gene_ids is mandatory")
829-
830-
# gene_ids = body['gene_ids']
831-
# if not isinstance(gene_ids, list):
832-
# abort(400, "gene_ids must be a list")
833-
# if len(gene_ids) == 0:
834-
# abort(400, "gene_ids must contain at least one gene symbol")
798+
@swag_from("swagger_specs/pathwaysInCommon.yml")
799+
def pathways_in_common():
800+
body = request.get_json() # type: ignore
801+
if "gene_ids" not in body:
802+
abort(400, "gene_ids is mandatory")
803+
804+
gene_ids = body['gene_ids']
805+
if not isinstance(gene_ids, list):
806+
abort(400, "gene_ids must be a list")
807+
if len(gene_ids) == 0:
808+
abort(400, "gene_ids must contain at least one gene symbol")
835809

836810
pathways_tmp = [get_pathways_of_gene(gene) for gene in gene_ids]
837811
pathways_intersection = list(set.intersection(*map(set, pathways_tmp)))
@@ -842,36 +816,35 @@ def pathways_in_common(gene_ids: List[str]):
842816
return make_response(response, 200, headers)
843817

844818
@flask_app.route("/expression-of-genes", methods=['POST'])
845-
# @doc(description='Gets gene expression in healthy tissue', tags=['Expression Data'], consumes=["application/json"])
846-
# @use_kwargs(args=swagger_schemas.ExpressionOfGenesRequestSchema, location="json")
847-
def expression_data_from_gtex(gene_ids: list[str], tissue: str, type: str):
848-
# body = request.get_json() # type: ignore
819+
@swag_from("swagger_specs/expressionOfGenes.yml")
820+
def expression_data_from_gtex():
821+
body = request.get_json() # type: ignore
849822

850-
# if "gene_ids" not in body:
851-
# abort(400, "gene_ids is mandatory")
823+
if "gene_ids" not in body:
824+
abort(400, "gene_ids is mandatory")
852825

853-
# gene_ids = body['gene_ids']
854-
# if not isinstance(gene_ids, list):
855-
# abort(400, "gene_ids must be a list")
826+
gene_ids = body['gene_ids']
827+
if not isinstance(gene_ids, list):
828+
abort(400, "gene_ids must be a list")
856829

857-
# if len(gene_ids) == 0:
858-
# abort(400, "gene_ids must contain at least one gene symbol")
830+
if len(gene_ids) == 0:
831+
abort(400, "gene_ids must contain at least one gene symbol")
859832

860-
# if "tissue" not in body:
861-
# abort(400, "tissue is mandatory")
833+
if "tissue" not in body:
834+
abort(400, "tissue is mandatory")
862835

863-
# tissue = body['tissue']
864-
# if "type" in body:
865-
# if body['type'] not in ["gzip", "json"]:
866-
# abort(400, "allowed values for the 'type' key are 'json' or 'gzip'")
867-
# else:
868-
# type_response = body['type']
869-
# else:
870-
# type_response = 'json'
836+
tissue = body['tissue']
837+
if "type" in body:
838+
if body['type'] not in ["gzip", "json"]:
839+
abort(400, "allowed values for the 'type' key are 'json' or 'gzip'")
840+
else:
841+
type_response = body['type']
842+
else:
843+
type_response = 'json'
871844

872845
expression_data = get_expression_from_gtex(tissue, gene_ids)
873846

874-
if type == "gzip":
847+
if type_response == "gzip":
875848
content = gzip.compress(json.dumps(
876849
expression_data).encode('utf8'), 5)
877850
response = make_response(content)
@@ -881,9 +854,8 @@ def expression_data_from_gtex(gene_ids: list[str], tissue: str, type: str):
881854
return jsonify(expression_data)
882855

883856
@flask_app.route("/genes-to-terms", methods=['POST'])
884-
# @doc(description='Gene Ontology terms related to a list of genes', tags=['Gene Ontology'], consumes=["application/json"])
885-
# @use_kwargs(args=swagger_schemas.GenesToTermsRequestSchema, location="json")
886-
def genes_to_go_terms(gene_ids: list[str], filter_type: str, p_value_threshold: float|None, correction_method: str, relation_type: list[str], ontology_type: list[str]):
857+
@swag_from("swagger_specs/genesToTerms.yml")
858+
def genes_to_go_terms():
887859
"""Receives a list of genes and returns the related terms"""
888860
valid_filter_types = ["union", "intersection", "enrichment"]
889861
valid_ontology_types = ["biological_process",
@@ -970,6 +942,7 @@ def genes_to_go_terms(gene_ids: list[str], filter_type: str, p_value_threshold:
970942
return jsonify(response)
971943

972944
@flask_app.route("/related-terms", methods=['POST'])
945+
@swag_from("swagger_specs/relatedTerms.yml")
973946
def related_terms():
974947
"""Receives a term and returns the related terms"""
975948
valid_ontology_types = ["biological_process",
@@ -1017,19 +990,18 @@ def related_terms():
1017990
return jsonify(response)
1018991

1019992
@flask_app.route("/information-of-oncokb", methods=['POST'])
1020-
# @doc(description='Therapies and actionable genes in cancer', tags=['Genes'], consumes=["application/json"])
1021-
# @use_kwargs(args=swagger_schemas.InformationOfOncokbRequestSchema, location="json")
1022-
def oncokb_data(gene_ids: list[str], query: str):
1023-
# body = request.get_json() # type: ignore
993+
@swag_from("swagger_specs/informationOfOncokb.yml")
994+
def oncokb_data():
995+
body = request.get_json() # type: ignore
1024996

1025-
# if "gene_ids" not in body:
1026-
# abort(400, "gene_ids is mandatory")
997+
if "gene_ids" not in body:
998+
abort(400, "gene_ids is mandatory")
1027999

1028-
# gene_ids = body['gene_ids']
1029-
# query = "" if "query" not in body else body['query']
1000+
gene_ids = body['gene_ids']
1001+
query = "" if "query" not in body else body['query']
10301002

1031-
# if not isinstance(gene_ids, list):
1032-
# abort(400, "gene_ids must be a list")
1003+
if not isinstance(gene_ids, list):
1004+
abort(400, "gene_ids must be a list")
10331005

10341006
if len(gene_ids) == 0:
10351007
abort(400, "gene_ids must contain at least one gene symbol")
@@ -1039,6 +1011,7 @@ def oncokb_data(gene_ids: list[str], query: str):
10391011
return jsonify(data)
10401012

10411013
@flask_app.route("/drugs-pharm-gkb", methods=['POST'])
1014+
@swag_from("swagger_specs/cancerDrugsRelatedToGenes.yml")
10421015
def cancer_drugs_related_to_genes():
10431016
"""Receives genes and returns the related drugs"""
10441017
response = {}
@@ -1053,6 +1026,7 @@ def cancer_drugs_related_to_genes():
10531026
return jsonify(response)
10541027

10551028
@flask_app.route("/string-relations", methods=['POST'])
1029+
@swag_from("swagger_specs/stringRelations.yml")
10561030
def string_relations_to_gene():
10571031
body = request.get_json()
10581032
optionals = {}
@@ -1070,6 +1044,7 @@ def string_relations_to_gene():
10701044
return jsonify(res)
10711045

10721046
@flask_app.route("/drugs-regulating-gene/<gene_id>", methods=['GET'])
1047+
@swag_from("swagger_specs/drugsRegulatingGene.yml")
10731048
def drugs_regulating_gene(gene_id):
10741049
return {
10751050
"link": "https://go.drugbank.com/pharmaco/transcriptomics?q%5Bg%5B0%5D%5D%5Bm%5D=or&q%5Bg%5B0%5D%5D"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
tags:
2+
- Accionable Genes and Drugs
3+
summary: "Cancer related drugs"
4+
description: "Gets a list of drugs from the PharmGKB database related to a list of genes."
5+
operationId: "Cancer related drugs"
6+
requestBody:
7+
required: true
8+
content:
9+
application/json:
10+
schema:
11+
type: object
12+
properties:
13+
gene_ids:
14+
type: array
15+
description: "List of gene identifiers."
16+
items:
17+
type: string
18+
example: ["JAK2", "EGFR"]
19+
responses:
20+
200:
21+
description: "List of all information related to drugs and genes."
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
tags:
2+
- Accionable Genes and Drugs
3+
summary: "Drugs that regulate a gene expression."
4+
description: "Service that takes gene symbol and returns a link to https://go.drugbank.com with all the drugs that upregulate and down regulate its expresion. Useful for embeding."
5+
operationId: "Drugs that regulate genetic expression."
6+
parameters:
7+
- in: path
8+
name: gene_id
9+
description: "Identifier of the gene."
10+
required: true
11+
schema:
12+
type: string
13+
example: "TP53"
14+
responses:
15+
200:
16+
description: "URL that points to the information on the DrugBank website."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
tags:
2+
- Gene Expression
3+
summary: "Gene expression"
4+
description: "Gets gene expression in healthy tissue."
5+
operationId: "Gene expression in healthy tissues"
6+
requestBody:
7+
required: true
8+
content:
9+
application/json:
10+
schema:
11+
type: object
12+
properties:
13+
gene_ids:
14+
type: array
15+
description: "List of gene identifiers."
16+
items:
17+
type: string
18+
example: ["BRCA1", "BRCA2"]
19+
tissue:
20+
type: string
21+
enum:
22+
- Adipose Tissue
23+
- Adrenal Gland
24+
- Bladder
25+
- Blood
26+
- Blood Vessel
27+
- Brain
28+
- Breast
29+
- Cervix Uteri
30+
- Colon
31+
- Esophagus
32+
- Fallopian Tube
33+
- Heart
34+
- Kidney
35+
- Liver
36+
- Lung
37+
- Muscle
38+
- Nerve
39+
- Ovary
40+
- Pancreas
41+
- Pituitary
42+
- Prostate
43+
- Salivary Gland
44+
- Skin
45+
- Small Intestine
46+
- Spleen
47+
- Stomach
48+
- Testis
49+
- Thyroid
50+
- Uterus
51+
- Vagina
52+
example: "Skin"
53+
type:
54+
type: string
55+
enum:
56+
- json
57+
- gzip
58+
example: "gzip"
59+
responses:
60+
200:
61+
description: "Expression values ​​of each gene according to the GTEx database."

bio-api/swagger_specs/genesOfItsGroup.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
tags:
2-
- Genes information
2+
- Genes Information
33
summary: "Gene Groups"
44
description: "Gets the identifier of a gene, validates it and then returns the group of genes to which it belongs according to HGNC, and all the other genes that belong to the same group."
55
operationId: "Gene Groups"

0 commit comments

Comments
 (0)