Timezone lookup using latitude and longitud (part 2)

fastapi test project.

For the fastapi project we are going to use Sqlalchemy and postgresql taking some reference from the fastapi documentation.

# create a virtualenv, with any tool: poetry, pipenv, virtualenv module, etc 
pip install fastapi uvicorn aiofiles SQLAlchemy psycopg2-binary

project structure

.
├── Dockerfile
├── LICENSE
├── main.py
├── README.md
├── requirements.txt
└── timezone_utils
    ├── database.py
    ├── __init__.py
    ├── models.py
    ├── schemas.py
    └── utils.py

1 directory, 10 files

we define the models, schemas and engine for sqlalchemy and the api in the package timezone_utils

for the query of the timezone using sqlalchemy will be like this:

import sqlalchemy as sa
from sqlalchemy.orm import Session

from . import models, schemas


def get_timezone(db: Session, point: schemas.TimezoneInput) -> schemas.Timezone:
    name = db.query(models.Timezones.tzid).filter(
        sa.func.ST_Contains(
            models.Timezones.geom, sa.func.ST_MakePoint(
                point.longitude,
                point.latitude)
        )
    ).scalar()
    return schemas.Timezone(name=name)

similar to the query in SQL, but using sqlalchemy, for the api the endpoint will accept query parameters for latitude and longitude and return a json with the timezone name.

the endpoint is defined like this:

from fastapi import FastAPI, Depends, Query
from sqlalchemy.orm import Session

from timezone_utils import schemas, models, utils
from timezone_utils.database import engine, SessionLocal

models.Base.metadata.create_all(bind=engine)

tags_metadata = [
    {
        "name": "timezone",
        "description": "Find timezone"
    }
]

app = FastAPI(
    title="Timezone Lookup",
    description="Find timezone name using latitude and longitude",
    version="0.0.1",
    openapi_tags=tags_metadata
)


def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()


@app.get("/timezone", response_model=schemas.Timezone, tags=["timezone"])
async def get_timezone(
        latitude: float = Query(gt=-85, lt=85, default=0, example=12),
        longitude: float = Query(gt=-180, lt=180, default=0, example=-86),
        db: Session = Depends(get_db)
):
    point = schemas.TimezoneInput(latitude=latitude, longitude=longitude)
    return utils.get_timezone(db, point)

Then we can test using curl or the swagger ui from the api documentation.

curl -X GET "http://localhost:8000/timezone?latitude=16&longitude=-86" -H  "accept: application/json"

{
  "name": "America/Tegucigalpa"
}
/img/posts/uploads/2020/08/timezone-api.png

timezone-api

This also can be implemented in Go and using a key value db Boltdb go - version

reference:

project code python - version