33import json
44import gzip
55import logging
6+
7+ from flask import Flask , jsonify , make_response , abort , render_template , request
8+ from flasgger import Swagger , swag_from
69from db import get_mongo_connection
710from concurrent .futures import ThreadPoolExecutor
811import configparser
9- import urllib .parse
1012from typing import List , Dict , Optional , Any
11- from flask import Flask , jsonify , make_response , abort , render_template , request
1213from utils import map_gene
1314from gprofiler import GProfiler
1415
16+
1517# Gets production flag
1618IS_DEBUG : bool = os .environ .get ('DEBUG' , 'true' ) == 'true'
1719
@@ -515,9 +517,6 @@ def bfs_on_terms(term_id, relations: Optional[List[str]] = None, general_depth=0
515517 return list (graph .values ())
516518
517519
518- # PharmGKB
519-
520-
521520def cancer_drugs_related_to_gene (gene : str ) -> List :
522521 """
523522 Gets all cancer related drugs associated with a gene .
@@ -527,6 +526,7 @@ def cancer_drugs_related_to_gene(gene: str) -> List:
527526 collection_pharm = mydb ["pharmgkb" ]
528527 return list (collection_pharm .find ({"genes" : gene }, {"_id" : 0 }))
529528
529+
530530def get_data_from_oncokb (genes : List [str ], query : str ) -> Dict [str , Dict [str , Any ]]:
531531 """
532532 Gets all data from OncoKB database associated with a gene list.
@@ -643,33 +643,41 @@ def associated_string_genes(gene_symbol: str, min_combined_score: int = 400) ->
643643 return res
644644
645645
646- # Documentation of included services
647- services = [
648- {"name" : "Genes symbols validator" , "url" : "[POST] /gene-symbols" },
649- {"name" : "Genes symbols finder" , "url" : "[GET] /gene-symbols-finder" },
650- {"name" : "Genes information" , "url" : "[POST] /information-of-genes" },
651- {"name" : "Gene Groups" , "url" : "[GET] /genes-of-its-group/<gene_id>" },
652- {"name" : "Genes of a metabolic pathway" , "url" : "[GET] /pathway-genes/<source>/<external_id>" },
653- {"name" : "Metabolic pathways from different genes" , "url" : "[POST] /pathways-in-common" },
654- {"name" : "Gene expression" , "url" : "[POST] /expression-of-genes" },
655- {"name" : "Therapies and actionable genes in cancer" , "url" : "[POST] /information-of-oncokb" },
656- {"name" : "Gene Ontology terms related to a list of genes" , "url" : "[POST] /genes-to-terms" },
657- {"name" : "Gene Ontology terms related to another specific term" , "url" : "[POST] /related-terms" },
658- {"name" : "Cancer related drugs" , "url" : "[POST] /drugs-pharm-gkb" },
659- {"name" : "Predicted functional associations network" , "url" : "[POST] /string-relations" },
660- {"name" : "Drugs that regulate a gene" , "url" : "[GET] /drugs-regulating-gene/<gene_id>" }
661- ]
662-
663-
664646def create_app ():
665647 # Creates and configures the app
666648 flask_app = Flask (__name__ , instance_relative_config = True )
667649
650+ swagger_config = {
651+ "headers" : [
652+ ],
653+ "openapi" : "3.0.0" ,
654+ "specs" : [
655+ {
656+ "endpoint" : "swagger" ,
657+ "route" : "/apispec.json" ,
658+ "rule_filter" : lambda rule : True ,
659+ "model_filter" : lambda tag : True
660+ }
661+ ],
662+ "title" : "BioAPI" ,
663+ "uiversion" : 3 ,
664+ "version" : VERSION ,
665+ "termsOfService" : False ,
666+ "swagger_ui" : True ,
667+ "static_url_path" : "/" ,
668+ "specs_route" : "/apidocs/" ,
669+ "description" : """
670+ ## A powerful abstraction of genomics databases.
671+ BioAPI is part of the Multiomix project. For more information, visit our [website](https://omicsdatascience.org/).
672+ To contribute: [OmicsDatascience](https://github.com/omics-datascience/BioAPI)"""
673+ }
674+
675+ Swagger (flask_app , config = swagger_config )
676+
668677 # Endpoints
669678 @flask_app .route ("/" )
670679 def homepage ():
671- # return render_template('index.html', title=f"API v{VERSION}", services=services)
672- return render_template ('homepage.html' , version = VERSION , services = services )
680+ return render_template ('homepage.html' , version = VERSION )
673681
674682 @flask_app .route ("/ping" )
675683 def ping_ok ():
@@ -678,12 +686,13 @@ def ping_ok():
678686 return make_response (output , 200 , headers )
679687
680688 @flask_app .route ("/gene-symbols" , methods = ['POST' ])
689+ @swag_from ("swagger_specs/geneSymbols.yml" )
681690 def gene_symbols ():
682691 """Receives a list of gene IDs in any standard and returns the standardized corresponding gene IDs.
683692 In case it is not found it returns an empty list for the specific not found gene."""
684693 response = {}
685694 if request .method == 'POST' :
686- body = request .get_json () # type: ignore
695+ body = request .get_json ()
687696 if "gene_ids" not in body :
688697 abort (400 , "gene_ids is mandatory" )
689698
@@ -700,16 +709,17 @@ def gene_symbols():
700709 return make_response (response , 200 , headers )
701710
702711 @flask_app .route ("/gene-symbols-finder/" , methods = ['GET' ])
712+ @swag_from ("swagger_specs/geneSymbolFinder.yml" )
703713 def gene_symbol_finder ():
704714 """Takes a string of any length and returns a list of genes that contain that search criteria."""
705715 if "query" not in request .args :
706716 abort (400 , "'query' parameter is mandatory" )
707717 else :
708- query = request .args .get ('query' ) # type: ignore
718+ query = request .args .get ('query' )
709719
710720 limit = 50
711721 if "limit" in request .args :
712- limit_arg = request .args .get ('limit' ) # type: ignore
722+ limit_arg = request .args .get ('limit' )
713723 if limit_arg .isnumeric ():
714724 limit = int (limit_arg )
715725 else :
@@ -722,6 +732,7 @@ def gene_symbol_finder():
722732 abort (400 , e )
723733
724734 @flask_app .route ("/information-of-genes" , methods = ['POST' ])
735+ @swag_from ("swagger_specs/informationOfGenes.yml" )
725736 def information_of_genes ():
726737 """Receives a list of gene IDs and returns information about them."""
727738 body = request .get_json () # type: ignore
@@ -739,7 +750,8 @@ def information_of_genes():
739750 return make_response (response , 200 , headers )
740751
741752 @flask_app .route ("/genes-of-its-group/<gene_id>" , methods = ['GET' ])
742- def genes_in_the_same_group (gene_id ):
753+ @swag_from ("swagger_specs/genesOfItsGroup.yml" )
754+ def genes_in_the_same_group (gene_id : str ):
743755 response = {"gene_id" : None , "groups" : [],
744756 "locus_group" : None , "locus_type" : None }
745757 try :
@@ -774,6 +786,7 @@ def genes_in_the_same_group(gene_id):
774786 return make_response (response , 200 , headers )
775787
776788 @flask_app .route ("/pathway-genes/<pathway_source>/<pathway_id>" , methods = ['GET' ])
789+ @swag_from ("swagger_specs/genesOfMetabolicPathway.yml" )
777790 def pathway_genes (pathway_source , pathway_id ):
778791 if pathway_source .lower () not in PATHWAYS_SOURCES :
779792 abort (404 , f'{ pathway_source } is an invalid pathway source' )
@@ -782,6 +795,7 @@ def pathway_genes(pathway_source, pathway_id):
782795 return make_response (response , 200 , headers )
783796
784797 @flask_app .route ("/pathways-in-common" , methods = ['POST' ])
798+ @swag_from ("swagger_specs/pathwaysInCommon.yml" )
785799 def pathways_in_common ():
786800 body = request .get_json () # type: ignore
787801 if "gene_ids" not in body :
@@ -802,6 +816,7 @@ def pathways_in_common():
802816 return make_response (response , 200 , headers )
803817
804818 @flask_app .route ("/expression-of-genes" , methods = ['POST' ])
819+ @swag_from ("swagger_specs/expressionOfGenes.yml" )
805820 def expression_data_from_gtex ():
806821 body = request .get_json () # type: ignore
807822
@@ -839,6 +854,7 @@ def expression_data_from_gtex():
839854 return jsonify (expression_data )
840855
841856 @flask_app .route ("/genes-to-terms" , methods = ['POST' ])
857+ @swag_from ("swagger_specs/genesToTerms.yml" )
842858 def genes_to_go_terms ():
843859 """Receives a list of genes and returns the related terms"""
844860 valid_filter_types = ["union" , "intersection" , "enrichment" ]
@@ -926,6 +942,7 @@ def genes_to_go_terms():
926942 return jsonify (response )
927943
928944 @flask_app .route ("/related-terms" , methods = ['POST' ])
945+ @swag_from ("swagger_specs/relatedTerms.yml" )
929946 def related_terms ():
930947 """Receives a term and returns the related terms"""
931948 valid_ontology_types = ["biological_process" ,
@@ -973,6 +990,7 @@ def related_terms():
973990 return jsonify (response )
974991
975992 @flask_app .route ("/information-of-oncokb" , methods = ['POST' ])
993+ @swag_from ("swagger_specs/informationOfOncokb.yml" )
976994 def oncokb_data ():
977995 body = request .get_json () # type: ignore
978996
@@ -993,6 +1011,7 @@ def oncokb_data():
9931011 return jsonify (data )
9941012
9951013 @flask_app .route ("/drugs-pharm-gkb" , methods = ['POST' ])
1014+ @swag_from ("swagger_specs/cancerDrugsRelatedToGenes.yml" )
9961015 def cancer_drugs_related_to_genes ():
9971016 """Receives genes and returns the related drugs"""
9981017 response = {}
@@ -1007,6 +1026,7 @@ def cancer_drugs_related_to_genes():
10071026 return jsonify (response )
10081027
10091028 @flask_app .route ("/string-relations" , methods = ['POST' ])
1029+ @swag_from ("swagger_specs/stringRelations.yml" )
10101030 def string_relations_to_gene ():
10111031 body = request .get_json ()
10121032 optionals = {}
@@ -1024,6 +1044,7 @@ def string_relations_to_gene():
10241044 return jsonify (res )
10251045
10261046 @flask_app .route ("/drugs-regulating-gene/<gene_id>" , methods = ['GET' ])
1047+ @swag_from ("swagger_specs/drugsRegulatingGene.yml" )
10271048 def drugs_regulating_gene (gene_id ):
10281049 return {
10291050 "link" : "https://go.drugbank.com/pharmaco/transcriptomics?q%5Bg%5B0%5D%5D%5Bm%5D=or&q%5Bg%5B0%5D%5D"
0 commit comments