From 5ee17bf8243964ff95da5e2f9f62e09988af05c0 Mon Sep 17 00:00:00 2001 From: Kenzo-Hugo Hillion Date: Wed, 1 Apr 2020 17:39:59 +0200 Subject: [PATCH 1/3] Start adding fastapi independant fastapi service --- bioapi/Dockerfile | 3 +++ bioapi/app/main.py | 13 +++++++++++++ docker-compose.yaml | 11 +++++++++++ nginx/dev/nginx.conf | 18 +++++++++++++++++- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 bioapi/Dockerfile create mode 100644 bioapi/app/main.py diff --git a/bioapi/Dockerfile b/bioapi/Dockerfile new file mode 100644 index 0000000..1f36f1f --- /dev/null +++ b/bioapi/Dockerfile @@ -0,0 +1,3 @@ +FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7-alpine3.8 + +COPY ./app /app diff --git a/bioapi/app/main.py b/bioapi/app/main.py new file mode 100644 index 0000000..213a41a --- /dev/null +++ b/bioapi/app/main.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: str = None): + return {"item_id": item_id, "q": q} diff --git a/docker-compose.yaml b/docker-compose.yaml index 38fea5f..60a5c57 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -106,6 +106,17 @@ services: networks: - main + bioapi: + container_name: bioapi + build: + context: ./bioapi + ports: + - "81:80" + environment: + DEBUG: "true" + networks: + - main + volumes: postgresql-data: django-static: diff --git a/nginx/dev/nginx.conf b/nginx/dev/nginx.conf index 957ca61..7f57e52 100644 --- a/nginx/dev/nginx.conf +++ b/nginx/dev/nginx.conf @@ -13,6 +13,10 @@ http { server backend:8000; } + upstream bioapi { + server bioapi:80; + } + upstream frontend { server frontend:8080; } @@ -22,7 +26,7 @@ http { } upstream portainer { - server portainer:9000; + server portainer:9000; } server { @@ -56,6 +60,18 @@ http { proxy_set_header Host $http_host; } + # bioapi urls + location /bioapi/ { + proxy_pass http://bioapi/; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + } + location /openapi.json { # This need to be changed to be performed only locally to this /bioapi location + proxy_pass http://bioapi/openapi.json; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + } + # flower location /flower/ { rewrite ^/flower/(.*)$ /$1 break; -- GitLab From 648e08c4b9896700dd415372d54542a4d49244c4 Mon Sep 17 00:00:00 2001 From: Kenzo-Hugo Hillion Date: Thu, 2 Apr 2020 12:38:47 +0200 Subject: [PATCH 2/3] Add reload part for dev env --- bioapi/Dockerfile | 6 +++++- bioapi/app/main.py | 15 +++++++++++++++ bioapi/requirements.txt | 1 + docker-compose.yaml | 3 +++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 bioapi/requirements.txt diff --git a/bioapi/Dockerfile b/bioapi/Dockerfile index 1f36f1f..23f957a 100644 --- a/bioapi/Dockerfile +++ b/bioapi/Dockerfile @@ -1,3 +1,7 @@ FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7-alpine3.8 -COPY ./app /app +RUN apk add --no-cache git + +COPY ./requirements.txt requirements.txt +RUN pip install --upgrade pip +RUN pip install -r requirements.txt diff --git a/bioapi/app/main.py b/bioapi/app/main.py index 213a41a..eb2ee3e 100644 --- a/bioapi/app/main.py +++ b/bioapi/app/main.py @@ -1,6 +1,10 @@ +import logging + from fastapi import FastAPI +from bioapi.togows import TogoWSEntryAPI app = FastAPI() +logger = logging.getLogger(__name__) @app.get("/") @@ -11,3 +15,14 @@ def read_root(): @app.get("/items/{item_id}") def read_item(item_id: int, q: str = None): return {"item_id": item_id, "q": q} + + +@app.get("/kegg-orthology/{kegg_id}") +def kegg_orthology(kegg_id: str): + kegg_api = TogoWSEntryAPI("kegg-orthology") + response = kegg_api.get(kegg_id)[0] + response["source_information"] = { + 'comment': f"Information retrieved from external source: {kegg_api.url}", + 'url': f"{kegg_api.url}{kegg_id}" + } + return response diff --git a/bioapi/requirements.txt b/bioapi/requirements.txt new file mode 100644 index 0000000..990c80e --- /dev/null +++ b/bioapi/requirements.txt @@ -0,0 +1 @@ +git+https://github.com/khillion/bioapi.git#egg=bioapi diff --git a/docker-compose.yaml b/docker-compose.yaml index 60a5c57..41f1ed4 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -110,6 +110,9 @@ services: container_name: bioapi build: context: ./bioapi + volumes: + - ./bioapi/app:/app + entrypoint: /start-reload.sh ports: - "81:80" environment: -- GitLab From 17417e3457830d04ef48609c05399211f06b71dd Mon Sep 17 00:00:00 2001 From: Kenzo-Hugo Hillion Date: Wed, 8 Apr 2020 17:52:15 +0200 Subject: [PATCH 3/3] add kegg orthology endpoint with fastapi --- bioapi/README.md | 20 +++++ bioapi/app/__init__.py | 0 bioapi/app/main.py | 35 ++++----- bioapi/app/routers/__init__.py | 0 bioapi/app/routers/common/__init__.py | 0 .../app/routers/common/response/__init__.py | 0 bioapi/app/routers/common/response/model.py | 13 ++++ bioapi/app/routers/kegg_orthology.py | 73 +++++++++++++++++++ nginx/dev/nginx.conf | 5 -- 9 files changed, 120 insertions(+), 26 deletions(-) create mode 100644 bioapi/README.md create mode 100644 bioapi/app/__init__.py create mode 100644 bioapi/app/routers/__init__.py create mode 100644 bioapi/app/routers/common/__init__.py create mode 100644 bioapi/app/routers/common/response/__init__.py create mode 100644 bioapi/app/routers/common/response/model.py create mode 100644 bioapi/app/routers/kegg_orthology.py diff --git a/bioapi/README.md b/bioapi/README.md new file mode 100644 index 0000000..06f484a --- /dev/null +++ b/bioapi/README.md @@ -0,0 +1,20 @@ +# Bioapi Web service + +This is preliminary documentation for the service. + +This service aims to facilitate aquisition of information from external APIs with clean documentation and a common returned format. + +## Response format + +Each response is comprised two parts: + +```json +{ + 'info': {} + 'response': {} +} +``` + +The first `info` section contains information about the time the request was done on the server and which url has been requested. + +The `response` section contains the response from the API requested. diff --git a/bioapi/app/__init__.py b/bioapi/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bioapi/app/main.py b/bioapi/app/main.py index eb2ee3e..1c5e4f3 100644 --- a/bioapi/app/main.py +++ b/bioapi/app/main.py @@ -1,28 +1,21 @@ import logging from fastapi import FastAPI -from bioapi.togows import TogoWSEntryAPI -app = FastAPI() -logger = logging.getLogger(__name__) - - -@app.get("/") -def read_root(): - return {"Hello": "World"} +from routers import kegg_orthology - -@app.get("/items/{item_id}") -def read_item(item_id: int, q: str = None): - return {"item_id": item_id, "q": q} +app = FastAPI( + title="BioAPI", + description="Access external bioinformatics API", + version="0.0.1", + docs_url="/documentation", + openapi_prefix="/bioapi" +) +logger = logging.getLogger(__name__) -@app.get("/kegg-orthology/{kegg_id}") -def kegg_orthology(kegg_id: str): - kegg_api = TogoWSEntryAPI("kegg-orthology") - response = kegg_api.get(kegg_id)[0] - response["source_information"] = { - 'comment': f"Information retrieved from external source: {kegg_api.url}", - 'url': f"{kegg_api.url}{kegg_id}" - } - return response +app.include_router( + kegg_orthology.router, + prefix="/kegg-orthology", + tags=["KEGG"], +) diff --git a/bioapi/app/routers/__init__.py b/bioapi/app/routers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bioapi/app/routers/common/__init__.py b/bioapi/app/routers/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bioapi/app/routers/common/response/__init__.py b/bioapi/app/routers/common/response/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bioapi/app/routers/common/response/model.py b/bioapi/app/routers/common/response/model.py new file mode 100644 index 0000000..cda8c54 --- /dev/null +++ b/bioapi/app/routers/common/response/model.py @@ -0,0 +1,13 @@ +from datetime import datetime + +from pydantic import BaseModel, HttpUrl + + +class InfoModel(BaseModel): + time: datetime + requested_url: HttpUrl + + +class ResponseModel(BaseModel): + info: InfoModel + response: dict diff --git a/bioapi/app/routers/kegg_orthology.py b/bioapi/app/routers/kegg_orthology.py new file mode 100644 index 0000000..09e1336 --- /dev/null +++ b/bioapi/app/routers/kegg_orthology.py @@ -0,0 +1,73 @@ +from datetime import datetime + +from bioapi.togows import TogoWSEntryAPI +from fastapi import APIRouter, HTTPException, Path +from requests.exceptions import HTTPError + +from .common.response.model import ResponseModel + +router = APIRouter() + + +class KeggResponseModel(ResponseModel): + + class Config: + schema_extra = { + "example": { + "info": { + "time": "2020-04-08T10:12:37.815424", + "requested_url": "http://togows.org/entry/kegg-orthology/K06925.json" + }, + "response": { + "entry_id": "K06925", + "name": "tsaE", + "names": [ + "tsaE" + ], + "definition": "tRNA threonylcarbamoyladenosine biosynthesis protein TsaE", + "pathways": {}, + "modules": {}, + "classes": [], + "diseases": {}, + "dblinks": { + "COG": [ + "COG0802" + ] + }, + "genes": {}, + "references": [] + } + } + } + + +@router.get( + "/{kegg_id}", + response_model=KeggResponseModel, + summary="Retrieve Kegg orthology information through togows.org API", + response_description="KEGG entry at the JSON format", +) +async def kegg_orthology( + kegg_id: str = Path( + ..., + description="KEGG orthology ID", + regex="^K[0-9]{5}$" + ) + ): + """ + KEGG orthology ID have the format `KXXXXX`. *example*: `K06925` + + [More information about KEGG orthology](https://www.genome.jp/kegg/ko.html) + """ + kegg_api = TogoWSEntryAPI("kegg-orthology") + try: + response = kegg_api.get(kegg_id) + except HTTPError: + raise HTTPException(status_code=404, detail=f"{kegg_id} not found") + return { + 'info': { + 'time': datetime.now(), + 'requested_url': kegg_api.last_url_requested + }, + 'response': response + } diff --git a/nginx/dev/nginx.conf b/nginx/dev/nginx.conf index 7f57e52..e1c686e 100644 --- a/nginx/dev/nginx.conf +++ b/nginx/dev/nginx.conf @@ -66,11 +66,6 @@ http { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } - location /openapi.json { # This need to be changed to be performed only locally to this /bioapi location - proxy_pass http://bioapi/openapi.json; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - } # flower location /flower/ { -- GitLab