Skip to content

Commit

Permalink
add backend example
Browse files Browse the repository at this point in the history
  • Loading branch information
eeliu committed Nov 9, 2023
1 parent 23f39dc commit 9642191
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 0 deletions.
15 changes: 15 additions & 0 deletions testapps/backend.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.8
WORKDIR /app/

COPY testapps/backend/ /app/
RUN pip install -r requirements.txt

COPY setup.py /pinpoint-c-agent/setup.py
COPY common/ /pinpoint-c-agent/common
COPY README /pinpoint-c-agent/README
COPY plugins/PY /pinpoint-c-agent/plugins/PY
COPY src/PY /pinpoint-c-agent/src/PY
RUN cd /pinpoint-c-agent && pip install -e .

# EXPOSE 8000
CMD [ "uvicorn", "main:app","--host=0.0.0.0","--port=8000","--reload" ]
Empty file added testapps/backend/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions testapps/backend/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from sqlalchemy.orm import Session

import models, schemas


def get_user(db: Session, user_id: int):
return db.query(models.User).filter(models.User.id == user_id).first()


def get_user_by_email(db: Session, email: str):
return db.query(models.User).filter(models.User.email == email).first()


def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.User).offset(skip).limit(limit).all()


def create_user(db: Session, user: schemas.UserCreate):
fake_hashed_password = user.password + "notreallyhashed"
db_user = models.User(email=user.email, hashed_password=fake_hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user


def get_items(db: Session, skip: int = 0, limit: int = 100):
return db.query(models.Item).offset(skip).limit(limit).all()


def create_user_item(db: Session, item: schemas.ItemCreate, user_id: int):
db_item = models.Item(**item.dict(), owner_id=user_id)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
13 changes: 13 additions & 0 deletions testapps/backend/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"
SQLALCHEMY_DATABASE_URL = "mysql+pymysql://root:password@dev-mysql/employees?charset=utf8mb4"

engine = create_engine(
SQLALCHEMY_DATABASE_URL
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()
135 changes: 135 additions & 0 deletions testapps/backend/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from fastapi import FastAPI, Request, Response, Depends, HTTPException
from starlette.middleware import Middleware
from pinpointPy.Fastapi import PinPointMiddleWare, async_monkey_patch_for_pinpoint
from pinpointPy import set_agent
from sqlalchemy.orm import Session
from starlette_context.middleware import ContextMiddleware
import aioredis
from contextlib import asynccontextmanager
import httpx
from typing import List

import crud
import models
import schemas

from database import SessionLocal, engine

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

redis = aioredis.from_url('redis://redis:6379', decode_responses=True)


class UserMiddleWare(PinPointMiddleWare):
async def dispatch(self, request: Request, call_next):
if request.url.path in ["/heartbeat", "/l7check"]:
return await call_next(request)
else:
return await super().dispatch(request, call_next)


middleware = [
Middleware(ContextMiddleware),
Middleware(UserMiddleWare)
]

async_monkey_patch_for_pinpoint()

set_agent("cd.dev.test.py.backend", "cd.dev.test.py.backend", 'tcp:dev-collector:10000')


@asynccontextmanager
async def lifespan(app: FastAPI):
app.requests_client = httpx.AsyncClient()
yield
await app.requests_client.aclose()

app = FastAPI(title='FastAPI Pinpoint Example',
middleware=middleware, lifespan=lifespan)


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


@app.middleware("http")
async def db_session_middleware(request: Request, call_next):
response = Response("Internal server error", status_code=500)
try:
request.state.db = SessionLocal()
response = await call_next(request)
finally:
request.state.db.close()
return response


def get_db(request: Request):
return request.state.db


@app.get("/")
async def root():
return {"message": "Hello World"}


@app.get("/test-redis/set/{uid}", tags=["redis"])
async def test_redis(uid: str = "default"):
await redis.set(uid, "50fdf310-7d3b-11ee-b962-0242ac120002", ex=1)
in_value = await redis.get(uid)
return {"uid": in_value}


@app.get("/httpx/example", tags=["httpx"])
async def test_httpx(request: Request, url='http://www.example.com/'):
requests_client = request.app.requests_client
print(request.headers)
response = await requests_client.get(url)
return {"response": response.status_code}


@app.get("/httpx-self/", tags=["httpx"])
async def test_httpx(request: Request):
requests_client = request.app.requests_client
response = await requests_client.get('http://127.0.0.1:8000/httpx/example')
return {"response": response.status_code}

# thanks guide from https://fastapi.tiangolo.com/tutorial/sql-databases/


@app.post("/users/", response_model=schemas.User, tags=["mysql"])
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = crud.get_user_by_email(db, email=user.email)
if db_user:
raise HTTPException(status_code=400, detail="Email already registered")
return crud.create_user(db=db, user=user)


@app.get("/users/", response_model=List[schemas.User], tags=["mysql"])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_users(db, skip=skip, limit=limit)
return users


@app.get("/users/{user_id}", response_model=schemas.User, tags=["mysql"])
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user


@app.post("/users/{user_id}/items/", response_model=schemas.Item, tags=["mysql"])
def create_item_for_user(
user_id: int, item: schemas.ItemCreate, db: Session = Depends(get_db)
):
return crud.create_user_item(db=db, item=item, user_id=user_id)


@app.get("/items/", response_model=List[schemas.Item], tags=["mysql"])
def read_items(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
items = crud.get_items(db, skip=skip, limit=limit)
return items
26 changes: 26 additions & 0 deletions testapps/backend/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship

from database import Base


class User(Base):
__tablename__ = "users"

id = Column(Integer, primary_key=True, index=True)
email = Column(String(20), unique=True, index=True)
hashed_password = Column(String(36))
is_active = Column(Boolean, default=True)

items = relationship("Item", back_populates="owner")


class Item(Base):
__tablename__ = "items"

id = Column(Integer, primary_key=True, index=True)
title = Column(String(128), index=True)
description = Column(String(256), index=True)
owner_id = Column(Integer, ForeignKey("users.id"))

owner = relationship("User", back_populates="items")
9 changes: 9 additions & 0 deletions testapps/backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
aioredis==2.0.1
fastapi
httpx==0.25.1
pydantic==2.4.2
SQLAlchemy==2.0.23
starlette
starlette_context
uvicorn
pymysql
37 changes: 37 additions & 0 deletions testapps/backend/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import List, Union

from pydantic import BaseModel


class ItemBase(BaseModel):
title: str
description: Union[str, None] = None


class ItemCreate(ItemBase):
pass


class Item(ItemBase):
id: int
owner_id: int

class Config:
orm_mode = True


class UserBase(BaseModel):
email: str


class UserCreate(UserBase):
password: str


class User(UserBase):
id: int
is_active: bool
items: List[Item] = []

class Config:
orm_mode = True
8 changes: 8 additions & 0 deletions testapps/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ services:
context: ../
ports:
- 8186:8000

backend:
restart: always
build:
dockerfile: testapps/backend.dockerfile
context: ../
ports:
- 8187:8000

dev-collector:
restart: always
Expand Down
8 changes: 8 additions & 0 deletions testapps/fastapi/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ async def test_httpx(request: Request, url='http://www.example.com/'):
return {"response": response.status_code}


@app.get("/httpx/backend", tags=["httpx"])
async def test_httpx_backend(request: Request, url='http://backend:8000/'):
requests_client = request.app.requests_client
print(request.headers)
response = await requests_client.get(url)
return {"response": response.status_code}


@app.get("/httpx-self/", tags=["httpx"])
async def test_httpx(request: Request):
requests_client = request.app.requests_client
Expand Down

0 comments on commit 9642191

Please sign in to comment.