Skip to content

Commit ff72e67

Browse files
committed
Celery tasks have been created
The data is fetched from ipdata.co and saved to the database by using background workers
1 parent 3d4056e commit ff72e67

16 files changed

+145
-64
lines changed

api/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from fastapi import APIRouter
22

3-
from .endpoints import user, tasks, basic, users, items
3+
from .endpoints import user, tasks
4+
from .endpoints import tutorial, users, items
45

56
api_router = APIRouter()
67
api_router.include_router(user.router, tags=["user"])
78
api_router.include_router(tasks.router, tags=["tasks"])
89

9-
api_router.include_router(basic.router, prefix="/basic", tags=["basic"])
10+
api_router.include_router(tutorial.router, prefix="/tutorial", tags=["tutorial"])
1011
api_router.include_router(users.router, prefix="/users", tags=["users"])
1112
api_router.include_router(items.router, prefix="/items", tags=["items"])

api/endpoints/basic.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

api/endpoints/items.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ def user_items(Authorize: AuthJWT = Depends(), skip: int = 0, limit: int = 100):
2323
dependencies=[Depends(get_db)],
2424
)
2525
def create_item_for_user(user_id: int, item: ItemCreate):
26-
return crud_items.create_user_item(item=item, user_id=user_id)
26+
return crud_items.create_user_item(item=item, user_id=user_id)

api/endpoints/tasks.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
1-
from fastapi import APIRouter
2-
from pydantic import BaseModel
1+
from fastapi import APIRouter, Depends, Request
2+
from fastapi_jwt_auth import AuthJWT
33

4-
from celery_worker import add
4+
from celery.result import AsyncResult
5+
from celery_worker import celery as celery_app, user_ip_data_save
56

7+
from crud import ipdata as crud_ipdata
8+
from schemas.ipdata import IPDataCreate
69

710
router = APIRouter()
811

912

10-
# Use pydantic to keep track of the input request payload
11-
class Numbers(BaseModel):
12-
x: float
13-
y: float
13+
@router.post('/task/')
14+
def enqueue_user_ip_data(ipdata: IPDataCreate, Authorize: AuthJWT = Depends()):
15+
Authorize.jwt_required()
1416

17+
db_ipdata = crud_ipdata.get_by_ip_address(ipdata.ip_address)
18+
if db_ipdata:
19+
return {"msg": "The details of this IP exist in the database."}
1520

16-
@router.post('/task/')
17-
def enqueue_add(n: Numbers):
18-
# We use celery delay method in order to enqueue the task with the given parameters
19-
add.delay(n.x, n.y)
21+
task = user_ip_data_save.delay(ipdata.ip_address)
22+
return {"msg": "Task has been created.", "task_id": task.id}
23+
24+
25+
@router.get("/status/{id}/")
26+
async def check_task_status(task_id: str):
27+
result = AsyncResult(task_id, app=celery_app)
28+
return {"status": result.state}

api/endpoints/tutorial.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from fastapi import APIRouter, Request
2+
3+
from celery_worker import add
4+
from schemas.tutorial import Numbers
5+
6+
router = APIRouter()
7+
8+
9+
@router.get("/")
10+
async def root():
11+
return {"message": "Hello World!"}
12+
13+
14+
@router.get("/hello/{name}")
15+
async def say_hello(name: str):
16+
return {"message": f"Hello {name}"}
17+
18+
19+
@router.get("/my-ip/")
20+
async def show_user_ip(request: Request):
21+
client_host = request.client.host
22+
return {"client_host": client_host}
23+
24+
25+
@router.post('/sum/')
26+
def enqueue_add(n: Numbers):
27+
add.delay(n.x, n.y)
28+
# We use celery delay method in order to enqueue the
29+
# task with the given parameters

celery_worker.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from celery import Celery
22
from celery.utils.log import get_task_logger
3-
from core import settings
43

4+
from core import settings
5+
from db.models import IPData as model_IPData
6+
from crud.ipdata import get_user_ip_data
57

68
celery = Celery(__name__)
79
celery.conf.broker_url = settings.CELERY_BROKER_URL
@@ -10,6 +12,17 @@
1012
logger = get_task_logger(__name__)
1113

1214

15+
@celery.task
16+
def user_ip_data_save(ip_address):
17+
ip_data_obj = model_IPData(
18+
ip_address=ip_address,
19+
ip_details=get_user_ip_data(ip_address),
20+
)
21+
ip_data_obj.save()
22+
23+
return ip_data_obj
24+
25+
1326
@celery.task
1427
def add(x, y):
1528
res = x + y

core/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
class FastAPISettings:
1010
API_V1_STR: str = "/api/v1"
11-
1211
IPDATA_API_KEY: str = env("IPDATA_API_KEY", default="test")
12+
1313
AUTH_JWT_SECRET_KEY: str = env("AUTH_JWT_SECRET_KEY", default="secret")
1414
AUTH_JWT_TOKEN_ALGORITHM = "HS256"
1515
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 1

core/utils.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import json
22

33

4-
def json_prettify(json_dict):
5-
return json.loads(
6-
json.dumps(
7-
json_dict,
8-
ensure_ascii=False,
9-
allow_nan=False,
10-
indent=4,
11-
separators=(", ", ": "),
12-
).encode("utf-8")
4+
def prettify_json(json_dict) -> str:
5+
return json.dumps(
6+
json_dict,
7+
ensure_ascii=False,
8+
allow_nan=False,
9+
indent=4,
10+
separators=(", ", ": "),
1311
)

crud/ipdata.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import aiohttp
2+
import requests
3+
4+
from core import settings
5+
from core.utils import prettify_json
6+
from db.models import IPData as model_IPData
7+
8+
9+
def get_by_ip_address(ip_address: str):
10+
return model_IPData.filter(model_IPData.ip_address == ip_address).first()
11+
12+
13+
def get_user_ip_data(client_ip):
14+
ip_data_url = f"https://api.ipdata.co/{client_ip}?api-key={settings.IPDATA_API_KEY}"
15+
response = requests.get(ip_data_url)
16+
return prettify_json(response.json())
17+
18+
19+
async def get_user_ip_data_async(client_ip):
20+
ip_data_url = f"https://api.ipdata.co/{client_ip}?api-key={settings.IPDATA_API_KEY}"
21+
async with aiohttp.ClientSession() as session:
22+
async with session.get(ip_data_url) as response:
23+
json_dict = await response.json()
24+
25+
return prettify_json(json_dict)
26+
27+
28+

db/models.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,18 @@ class Meta:
1313
database = mysql_db
1414

1515

16+
class IPData(peewee.Model):
17+
ip_address = peewee.CharField()
18+
ip_details = peewee.TextField()
19+
20+
class Meta:
21+
database = mysql_db
22+
23+
1624
class Item(peewee.Model):
1725
title = peewee.CharField(index=True)
1826
description = peewee.CharField(index=True)
19-
owner = peewee.ForeignKeyField(User, backref="items")
27+
user = peewee.ForeignKeyField(User, backref="items")
2028

2129
class Meta:
2230
database = mysql_db

main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from api import api_router
1212

1313
mysql_db.connect()
14-
mysql_db.create_tables([models.User, models.Item])
14+
mysql_db.create_tables([models.User, models.IPData, models.Item])
1515
mysql_db.close()
1616

1717
app = FastAPI(

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pymysql~=1.0.2
77
cryptography~=36.0.1
88
environs~=9.5.0
99
aiohttp~=3.8.1
10+
requests~=2.27.1
1011
fastapi-jwt-auth~=0.5.0
1112
passlib[bcrypt]~=1.7.4
1213
celery~=5.2.3

schemas/ipdata.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import Optional
2+
from pydantic import BaseModel
3+
4+
from .utils import PeeweeGetterDict
5+
6+
7+
class IPDataBase(BaseModel):
8+
ip_address: str
9+
10+
11+
class IPDataCreate(IPDataBase):
12+
pass
13+
14+
15+
class IPData(IPDataCreate):
16+
id: Optional[int] = None
17+
ip_details: Optional[str]
18+
# user_id: int
19+
20+
class Config:
21+
orm_mode = True
22+
getter_dict = PeeweeGetterDict

schemas/item.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ItemCreate(ItemBase):
1515

1616
class Item(ItemBase):
1717
id: int
18-
owner_id: int
18+
user_id: int
1919

2020
class Config:
2121
orm_mode = True

schemas/tutorial.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from pydantic import BaseModel
2+
3+
4+
class Numbers(BaseModel):
5+
x: float
6+
y: float

schemas/user.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from .utils import PeeweeGetterDict
55
from .item import Item
6+
from .ipdata import IPData
67

78

89
class UserBase(BaseModel):
@@ -26,6 +27,7 @@ class UserCreate(UserBase):
2627
class UserInDBBase(UserBase):
2728
id: Optional[int] = None
2829
items: List[Item] = []
30+
ipdata: IPData = None
2931

3032
class Config:
3133
orm_mode = True

0 commit comments

Comments
 (0)