Skip to content

Commit

Permalink
docs(api-description): adds parameters and endpoints descriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
nifedara committed Aug 14, 2024
1 parent 5adc8a9 commit 13a848d
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 46 deletions.
29 changes: 19 additions & 10 deletions API/auth/routers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import json

from fastapi import APIRouter, Depends, Request
from fastapi import APIRouter, Depends, Request, Path, Query
from pydantic import BaseModel

from src.app import Users
Expand All @@ -12,7 +10,8 @@

@router.get("/login/")
def login_url(request: Request):
"""Generate Login URL for authentication using OAuth2 Application registered with OpenStreetMap.
"""
Generate Login URL for authentication using OAuth2 Application registered with OpenStreetMap.
Click on the download url returned to get access_token.
Parameters: None
Expand Down Expand Up @@ -42,14 +41,14 @@ def callback(request: Request):
return access_token


@router.get("/me/", response_model=AuthUser)
@router.get("/me/", response_model=AuthUser, response_description="User's Information")
def my_data(user_data: AuthUser = Depends(login_required)):
"""Read the access token and provide user details from OSM user's API endpoint,
also integrated with underpass .
Parameters:None
Returns: user_data
Returns: user_data\n
User Role :
ADMIN = 1
STAFF = 2
Expand Down Expand Up @@ -88,7 +87,10 @@ async def create_user(params: User, user_data: AuthUser = Depends(admin_required

# Read user by osm_id
@router.get("/users/{osm_id}", response_model=dict)
async def read_user(osm_id: int, user_data: AuthUser = Depends(staff_required)):
async def read_user(
osm_id: int = Path(description="The OSM ID of the User to Retrieve"),
user_data: AuthUser = Depends(staff_required),
):
"""
Retrieves user information based on the given osm_id.
User Role :
Expand All @@ -113,7 +115,9 @@ async def read_user(osm_id: int, user_data: AuthUser = Depends(staff_required)):
# Update user by osm_id
@router.put("/users/{osm_id}", response_model=dict)
async def update_user(
osm_id: int, update_data: User, user_data: AuthUser = Depends(admin_required)
update_data: User,
user_data: AuthUser = Depends(admin_required),
osm_id: int = Path(description="The OSM ID of the User to Update"),
):
"""
Updates user information based on the given osm_id.
Expand All @@ -137,7 +141,10 @@ async def update_user(

# Delete user by osm_id
@router.delete("/users/{osm_id}", response_model=dict)
async def delete_user(osm_id: int, user_data: AuthUser = Depends(admin_required)):
async def delete_user(
user_data: AuthUser = Depends(admin_required),
osm_id: int = Path(description="The OSM ID of the User to Delete"),
):
"""
Deletes a user based on the given osm_id.
Expand All @@ -157,7 +164,9 @@ async def delete_user(osm_id: int, user_data: AuthUser = Depends(admin_required)
# Get all users
@router.get("/users/", response_model=list)
async def read_users(
skip: int = 0, limit: int = 10, user_data: AuthUser = Depends(staff_required)
skip: int = Query(0, description="The Number of Users to Skip"),
limit: int = Query(10, description="The Maximum Number of Users to Retrieve"),
user_data: AuthUser = Depends(staff_required),
):
"""
Retrieves a list of users with optional pagination.
Expand Down
40 changes: 22 additions & 18 deletions API/hdx.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, List

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Path
from fastapi_versioning import version

from src.app import HDX
Expand All @@ -25,8 +25,8 @@ async def create_hdx(
Create a new HDX entry.
Args:
request (Request): The request object.
hdx_data (dict): Data for creating the HDX entry.
request (Request): The request object.\n
hdx_data (dict): Data for creating the HDX entry.\n
user_data (AuthUser): User authentication data.
Returns:
Expand All @@ -41,8 +41,8 @@ async def create_hdx(
@version(1)
async def read_hdx_list(
request: Request,
skip: int = 0,
limit: int = 10,
skip: int = Query(0, description="Number of entries to skip."),
limit: int = Query(10, description="Maximum number of entries to retrieve."),
):
"""
Retrieve a list of HDX entries based on provided filters.
Expand All @@ -65,7 +65,7 @@ async def read_hdx_list(
filters[f"dataset->>'{key}' = %s"] = values
try:
hdx_list = hdx_instance.get_hdx_list_with_filters(skip, limit, filters)
except Exception as ex:
except Exception:
raise HTTPException(status_code=422, detail="Couldn't process query")
return hdx_list

Expand Down Expand Up @@ -101,7 +101,9 @@ async def search_hdx(
@router.get("/{hdx_id}", response_model=dict)
@limiter.limit(f"{RATE_LIMIT_PER_MIN}/minute")
@version(1)
async def read_hdx(request: Request, hdx_id: int):
async def read_hdx(
request: Request, hdx_id: int = Path(description="ID of the HDX entry to retrieve")
):
"""
Retrieve a specific HDX entry by its ID.
Expand All @@ -127,17 +129,17 @@ async def read_hdx(request: Request, hdx_id: int):
@version(1)
async def update_hdx(
request: Request,
hdx_id: int,
hdx_data: dict,
hdx_id: int = Path(description="ID of the HDX entry to update"),
user_data: AuthUser = Depends(staff_required),
):
"""
Update an existing HDX entry.
Args:
request (Request): The request object.
hdx_id (int): ID of the HDX entry to update.
hdx_data (dict): Data for updating the HDX entry.
request (Request): The request object.\n
hdx_id (int): ID of the HDX entry to update.\n
hdx_data (dict): Data for updating the HDX entry.\n
user_data (AuthUser): User authentication data.
Returns:
Expand All @@ -159,17 +161,17 @@ async def update_hdx(
@version(1)
async def patch_hdx(
request: Request,
hdx_id: int,
hdx_data: Dict,
hdx_id: int = Path(description="ID of the HDX entry to update"),
user_data: AuthUser = Depends(staff_required),
):
"""
Partially update an existing HDX entry.
Args:
request (Request): The request object.
hdx_id (int): ID of the HDX entry to update.
hdx_data (Dict): Data for partially updating the HDX entry.
request (Request): The request object.\n
hdx_id (int): ID of the HDX entry to update.\n
hdx_data (Dict): Data for partially updating the HDX entry.\n
user_data (AuthUser): User authentication data.
Returns:
Expand All @@ -190,14 +192,16 @@ async def patch_hdx(
@limiter.limit(f"{RATE_LIMIT_PER_MIN}/minute")
@version(1)
async def delete_hdx(
request: Request, hdx_id: int, user_data: AuthUser = Depends(admin_required)
request: Request,
hdx_id: int = Path(description="ID of the HDX entry to delete"),
user_data: AuthUser = Depends(admin_required),
):
"""
Delete an existing HDX entry.
Args:
request (Request): The request object.
hdx_id (int): ID of the HDX entry to delete.
request (Request): The request object.\n
hdx_id (int): ID of the HDX entry to delete.\n
user_data (AuthUser): User authentication data.
Returns:
Expand Down
7 changes: 6 additions & 1 deletion API/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@

os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

app = FastAPI(title="Raw Data API ", swagger_ui_parameters={"syntaxHighlight": False})
app = FastAPI(
title="Raw Data API ",
description="""The Raw Data API allows you to transform
and export OpenStreetMap (OSM) data in different GIS file formats""",
swagger_ui_parameters={"syntaxHighlight": False},
)
app.include_router(auth_router)
app.include_router(raw_data_router)
app.include_router(tasks_router)
Expand Down
32 changes: 25 additions & 7 deletions API/raw_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
# 1100 13th Street NW Suite 800 Washington, D.C. 20005
# <info@hotosm.org>

"""[Router Responsible for Raw data API ]
"""
"""[Router Responsible for Raw data API ]"""

# Standard library imports
import json
from typing import AsyncGenerator
Expand All @@ -27,7 +27,7 @@
import orjson
import redis
from area import area
from fastapi import APIRouter, Body, Depends, HTTPException, Request
from fastapi import APIRouter, Body, Depends, HTTPException, Request, Path, Query
from fastapi.responses import JSONResponse, StreamingResponse
from fastapi_versioning import version

Expand Down Expand Up @@ -60,7 +60,7 @@
@router.get("/status/", response_model=StatusResponse)
@version(1)
def check_database_last_updated():
"""Gives status about how recent the osm data is , it will give the last time that database was updated completely"""
"""Gives status about how recent the osm data is. It will give the last time that database was updated completely"""
result = RawData().check_status()
return {"last_updated": result}

Expand Down Expand Up @@ -456,7 +456,7 @@ def get_osm_current_snapshot_as_file(
status_code=403,
detail=[
{
"msg": "Insufficient Permission for extracting exports with user metadata , Please login first"
"msg": "Insufficient Permission for extracting exports with user metadata, Please login first"
}
],
)
Expand Down Expand Up @@ -546,7 +546,17 @@ async def generate_geojson() -> AsyncGenerator[bytes, None]:

@router.get("/countries/")
@version(1)
def get_countries(q: str = ""):
def get_countries(
q: str = Query("", description="Query parameter for filtering countries"),
):
"""
Gets Countries list from the database
Args:
q (str): query parameter for filtering countries
Returns:
featurecollection: geojson of country
"""

result = RawData().get_countries_list(q)
return result

Expand All @@ -560,5 +570,13 @@ def get_specific_country(cid: int):

@router.get("/osm_id/")
@version(1)
def get_osm_feature(osm_id: int):
def get_osm_feature(osm_id: int = Path(description="The OSM ID of feature")):
"""
Gets geometry of osm_id in geojson
Args:
osm_id (int): osm_id of feature
Returns:
featurecollection: Geojson
"""

return RawData().get_osm_feature(osm_id)
7 changes: 3 additions & 4 deletions API/s3.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import json
from urllib.parse import quote

import boto3
import humanize
from boto3.session import Session
from botocore.exceptions import NoCredentialsError
from fastapi import APIRouter, Header, HTTPException, Path, Query, Request
from fastapi import APIRouter, HTTPException, Path, Query, Request
from fastapi.encoders import jsonable_encoder
from fastapi.responses import (
JSONResponse,
Expand Down Expand Up @@ -37,7 +36,7 @@
@version(1)
async def list_s3_files(
request: Request,
folder: str = Query(default="/HDX"),
folder: str = Query("/HDX", description="Folder in S3"),
prettify: bool = Query(
default=False, description="Display size & date in human-readable format"
),
Expand Down Expand Up @@ -89,7 +88,7 @@ async def check_object_existence(bucket_name, file_path):
s3.head_object(Bucket=bucket_name, Key=file_path)
except NoCredentialsError:
raise HTTPException(status_code=500, detail="AWS credentials not available")
except Exception as e:
except Exception:
raise HTTPException(
status_code=404, detail=f"File or folder not found: {file_path}"
)
Expand Down
30 changes: 24 additions & 6 deletions API/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Third party imports
import redis
from celery.result import AsyncResult
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from fastapi import APIRouter, Depends, HTTPException, Query, Request, Path
from fastapi.responses import JSONResponse
from fastapi_versioning import version

Expand All @@ -14,15 +14,15 @@
from src.validation.models import SnapshotTaskResponse

from .api_worker import celery
from .auth import AuthUser, admin_required, login_required, staff_required
from .auth import AuthUser, admin_required, staff_required

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


@router.get("/status/{task_id}/", response_model=SnapshotTaskResponse)
@version(1)
def get_task_status(
task_id,
task_id=Path(description="Unique id provided on response from */snapshot/*"),
only_args: bool = Query(
default=False,
description="Fetches arguments of task",
Expand Down Expand Up @@ -84,8 +84,11 @@ def get_task_status(

@router.get("/revoke/{task_id}/")
@version(1)
def revoke_task(task_id, user: AuthUser = Depends(staff_required)):
"""Revokes task , Terminates if it is executing
def revoke_task(
task_id=Path(description="Unique id provided on response from */snapshot*"),
user: AuthUser = Depends(staff_required),
):
"""Revokes task, Terminates if it is executing
Args:
task_id (_type_): task id of raw data task
Expand Down Expand Up @@ -154,6 +157,7 @@ def ping_workers():
def discard_all_waiting_tasks(user: AuthUser = Depends(admin_required)):
"""
Discards all waiting tasks from the queue
Returns : Number of tasks discarded
"""
purged = celery.control.purge()
Expand All @@ -166,6 +170,11 @@ def discard_all_waiting_tasks(user: AuthUser = Depends(admin_required)):
@router.get("/queue/")
@version(1)
def get_queue_info():
"""
Get all the queues
Returns : The queues names and their lengths
"""
queue_info = {}
redis_client = redis.StrictRedis.from_url(CELERY_BROKER_URL)

Expand All @@ -183,12 +192,21 @@ def get_queue_info():
@router.get("/queue/details/{queue_name}/")
@version(1)
def get_list_details(
queue_name: str,
queue_name=Path(description="Name of queue to retrieve"),
args: bool = Query(
default=False,
description="Includes arguments of task",
),
):
"""
Retrieves queue information based on the given queue name
Args:
- queue_name (str): The name of the queue to retrieve.
Returns : The queue details
"""

if queue_name not in queues:
raise HTTPException(status_code=404, detail=f"Queue '{queue_name}' not found")
redis_client = redis.StrictRedis.from_url(CELERY_BROKER_URL)
Expand Down

0 comments on commit 13a848d

Please sign in to comment.