Skip to content

Commit

Permalink
Merge pull request #72 from hwakabh/refactor/70/v0_migration
Browse files Browse the repository at this point in the history
refactor: v0 API migrations
  • Loading branch information
hwakabh authored Jan 22, 2024
2 parents 61bcc0e + fc46066 commit ced05c3
Show file tree
Hide file tree
Showing 17 changed files with 559 additions and 369 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,24 @@ In CI pipeline, API key as environmental variables will be fetched from GitHub A

In production env, where we expect to run app on GKE, they are mounted to app with Secret resources.
But for security consideration, we will use Sealed Secret to hide confidential information from GitHub, so you have to install sealed-secret-controller first to the Kubernetes cluster that you will use need, if you use your BYO cluster.


## API directory layout

Application root for API: `app/*`
- `database.py` and `config.py`
- The configuration parameters for application
- Determine where/how to connect

API Specifics structures in `app/api/v1/*`
- `routers.py`: Application URL routings with CRUDs and Services
- Routers itself is responsible on dispatching, so that it lies on top with CRUDs/Services

- `cruds.py`: Database operations using with models
- `models.py`: Table definitions with ORM

- `services.py`: Operations with other services including external endpoints

- `schemas.py`: Contains Request/Response models

- `helpers.py`: Helper functions for CRUDs/Services
120 changes: 0 additions & 120 deletions app/api/v0/cruds.py

This file was deleted.

38 changes: 10 additions & 28 deletions app/api/v0/routers.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
from fastapi import APIRouter, requests

from .cruds import get_destination_from_skyscanner_by_random, get_near_airport
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from fastapi.requests import Request

from app.api.v0 import schemas

router = APIRouter()

@router.get('/')
def index():
return {"path": "v0 API root, /api/v0/"}


@router.get('/gacha')
def gacha_result():
#--- get ajax POST data
time_limit = requests.json["time_limit"]
expense_limit = requests.json["expense_limit"]
current_lat = requests.json["current_lat"]
current_lng = requests.json["current_lng"]
print("main.py ajax POST data - time_limit: " + time_limit)
print("main.py ajax POST data - expense_limit: " + expense_limit)
print("main.py ajax POST data - current_lat: " + current_lat)
print("main.py ajax POST data - current_lng: " + current_lng)

#--- search and get near airport from MySQL (airport table)
near_airport_IATA = get_near_airport(current_lat,current_lng)
print("main.py get values - near_airport_IATA: " + near_airport_IATA)

#--- search and get reachable location (airport and country) from skyscanner api
#--- exclude if time and travel expenses exceed the user input parameter
#--- select a country at random
destination = get_destination_from_skyscanner_by_random(near_airport_IATA,time_limit,expense_limit)
return destination
@router.get('/')
def index(req: Request) -> schemas.RootResponse:

return JSONResponse(content={
"path": req.url.path,
"detail": "v0 API has been deprecated, please access v1 API with /api/v1/"
})
10 changes: 10 additions & 0 deletions app/api/v0/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import BaseModel


class RootResponseBase(BaseModel):
pass


class RootResponse(RootResponseBase):
path: str
detail: str
164 changes: 139 additions & 25 deletions app/api/v1/cruds.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,151 @@
import json
import random

import requests
import mysql.connector as mydb
import numpy as np
from sqlalchemy.orm import Session
import httpx

def get_country():
# import data
try:
url = 'https://restcountries.com/v3.1/all?fields=region,name'
data = requests.get(url).json()
from app.api.v1 import models
from app.api.v1 import schemas
from app.api.v1.helpers import dist_on_sphere
from app.config import app_settings

except requests.exceptions.HTTPError as e:
print('HTTPError: ', e)

except json.JSONDecodeError as e:
print('JSONDecodeError: ', e)
# TODO: should be used with ORM
conn = mydb.connect(
host=app_settings.MYSQL_HOST,
user=app_settings.MYSQL_USER,
password=app_settings.MYSQL_PASSWORD,
database=app_settings.MYSQL_DATABASE,
charset="utf8"
)

# Select region randomly
region = []
for x in range(0,len(data)):
if data[x]['region'] != '':
region.append(data[x]['region'])

region_result = random.choice(list(set(region)))
print(f"Region selected: {region_result}")
def get_airports_from_db(db: Session) -> schemas.Airport:
return db.query(models.Airport).limit(5).all()

# Select country randomly
country = []
for x in range(0,len(data)):
if data[x]['region'] == region_result:
country.append(data[x]['name']['official'])

country_result = random.choice(country)
print(f"Country selected: {country_result}")
def get_destination():
#--- get ajax POST data
time_limit = httpx.json()["time_limit"]
expense_limit = httpx.json()["expense_limit"]
current_lat = httpx.json()["current_lat"]
current_lng = httpx.json()["current_lng"]
print("main.py ajax POST data - time_limit: " + time_limit)
print("main.py ajax POST data - expense_limit: " + expense_limit)
print("main.py ajax POST data - current_lat: " + current_lat)
print("main.py ajax POST data - current_lng: " + current_lng)

return country_result
#--- search and get near airport from MySQL (airport table)
near_airport_IATA = get_near_airport(current_lat,current_lng)
print("main.py get values - near_airport_IATA: " + near_airport_IATA)

#--- search and get reachable location (airport and country) from skyscanner api
#--- exclude if time and travel expenses exceed the user input parameter
#--- select a country at random
destination = get_destination_from_skyscanner_by_random(near_airport_IATA,time_limit,expense_limit)
return destination


# --- search and get near airport from MySQL (airport table)
def get_near_airport(current_lat,current_lng):

conn.ping(reconnect=True)
cur = conn.cursor()

print("gacha.py get values - current_lat: " + current_lat)
print("gacha.py get values - current_lng: " + current_lng)

current = float(current_lat), float(current_lng)
target = []
dist_result = []
search_key = []
count = 0

cur.execute('select id,IATA,Name,Country,City,Latitude,Longitude from airport where not IATA="NULL"')

for sql_result in cur.fetchall():
target = sql_result[5], sql_result[6]
dist = dist_on_sphere(current, target)
dist_result.append([count,sql_result[0],sql_result[1],sql_result[2],sql_result[3],sql_result[4],dist])
search_key.append(dist)
count = count + 1

cur.close()
conn.close()

#print(dist_result)
#print(search_key)

#--- return near airport IATA
return dist_result[np.argmin(search_key)][2]


#--- search and get reachable location (airport and country) from skyscanner api
#--- exclude if time and travel expenses exceed the user input parameter
#--- select a country at random
def get_destination_from_skyscanner_by_random(near_airport_IATA,time_limit,expense_limit):

print("gacha.py get values - near_airport_IATA: " + near_airport_IATA)
print("gacha.py get values - time_limit: " + time_limit)
print("gacha.py get values - expense_limit: " + expense_limit)

# --- search and get reachable location (airport and country) from skyscanner api
# --- exclude if time and travel expenses exceed the user input parameter

##########################################################################################
##################################### Update required #####################################
###########################################################################################

#reachable_airport_IATA = ["TXL","YTD","CQS","NYR","QFG","NZE","IWK"]

conn.ping(reconnect=True)
cur = conn.cursor()

cur.execute('select IATA from airport where not IATA="NULL"')
reachable_airport_IATA = []
for sql_result in cur.fetchall():
reachable_airport_IATA.append(sql_result[0])

cur.close()
conn.close()

##########################################################################################
##########################################################################################
##########################################################################################

#--- select a country at random
random_airport_IATA = random.choice(reachable_airport_IATA)

#--- get lat/lng of near and selected airport from MySQL (airport table)
conn.ping(reconnect=True)
cur = conn.cursor()

cur.execute('select Country,City,IATA,Name,Latitude,Longitude from airport where IATA="' + near_airport_IATA + '"')
transit = []
for sql_result in cur.fetchall():
transit.append([sql_result[0],sql_result[1],sql_result[2],sql_result[3],sql_result[4],sql_result[5]])

cur.execute('select Country,City,IATA,Name,Latitude,Longitude from airport where IATA="' + random_airport_IATA + '"')
destination = []
for sql_result in cur.fetchall():
destination.append([sql_result[0],sql_result[1],sql_result[2],sql_result[3],sql_result[4],sql_result[5]])

cur.close()
conn.close()

return json.dumps({
"tran_country":transit[0][0],
"tran_city":transit[0][1],
"tran_iata":transit[0][2],
"tran_airport":transit[0][3],
"tran_lat":transit[0][4],
"tran_lng":transit[0][5],
"dest_country":destination[0][0],
"dest_city":destination[0][1],
"dest_iata":destination[0][2],
"dest_airport":destination[0][3],
"dest_lat":destination[0][4],
"dest_lng":destination[0][5]
})
19 changes: 19 additions & 0 deletions app/api/v1/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from math import sin, cos, acos, radians


# Helper functions for cruds.py
#--- Distance calculation between two points
EARTH_RAD = 6378.137

def latlng_to_xyz(lat, lng):
rlat, rlng = radians(lat), radians(lng)
coslat = cos(rlat)
return coslat * cos(rlng), coslat * sin(rlng), sin(rlat)


def dist_on_sphere(pos0, pos1, radius=EARTH_RAD):
xyz0, xyz1 = latlng_to_xyz(*pos0), latlng_to_xyz(*pos1)
return acos(sum(x * y for x, y in zip(xyz0, xyz1)))*radius


# Helper functions for services.py
Loading

0 comments on commit ced05c3

Please sign in to comment.