Skip to content

Commit

Permalink
[IMP] sample example based on middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
smurf-U committed May 31, 2022
1 parent 2f318f8 commit 15ea50a
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 5,183 deletions.
83 changes: 59 additions & 24 deletions examples/sanic/README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,74 @@
# Sanic Sample Application for Pybrake

## About the application:
## About the application

The example application provides three GET endpoints:

1. `/date` - returns server date and time.
2. `/locations` - returns list of available locations.
1. `/date` - returns server date and time.
2. `/locations` - returns list of available locations.
3. `/weather/{locationName}` - returns the weather details for the locations.

## Steps to run the API:
## Steps to run the API

1. Install the dependencies for the application

```bash
pip3 install -r requirements.txt
```
```bash
pip install -r requirements.txt
```

2. Run the localhost server
2. You must get both `project_id` & `project_key`.

```bash
Sanic main.py
```
```bash
http://0.0.0.0:3000/
```
To find your `project_id` and `project_key` from Airbrake account and
replace it in below code in your project's `main.py` file.
3. To retrieve the responses, append the endpoints to the localhost URL with a `/`.
```python
from sanic import Sanic
from pybrake.middleware.sanic import init_app
app = Sanic()
app.config['PYBRAKE'] = dict(
project_id=999999, # Insert your Project Id here
project_key='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', # Insert your Project Key here
environment="test",
performance_stats=True, # False to disable APM
)
app = init_app(app)
```
Use the below curl commands to interact with the endpoints. The endpoints require an api-key HTTP header.
3. Run the localhost server
```bash
curl "http://localhost:3000/date/" -H 'api-key: b761be830f7c23ebe1c3250d42c43673'
curl "http://localhost:3000/locations/" -H 'api-key: b761be830f7c23ebe1c3250d42c43673'
curl "http://localhost:3000/weather/<austin/pune/santabarbara>/" -H 'api-key: b761be830f7c23ebe1c3250d42c43673'
curl "http://localhost:3000/weather/" -H 'api-key: b761be830f7c23ebe1c3250d42c43673'
```

The last curl command will raise `404 Not Found` error.
```bash
python main.py
```
```bash
http://0.0.0.0:3000/
```
4. To retrieve the responses, append the endpoints to the localhost URL.
Use the below curl commands to interact with the endpoints.
```bash
curl "http://localhost:3000/date"
curl "http://localhost:3000/locations"
curl "http://localhost:3000/weather/<austin/pune/santabarbara>"
```
The below curl command will raise `404 Not Found` error.
```bash
curl -I "http://localhost:3000/weather"
```
The below curl command will raise `500 Internal Server Error` error.
```bash
# Should produce an intentional HTTP 500 error and report the error to
# Airbrake (since `washington` is in the supported cities list but there
# is no data for `washington`, an `if` condition is bypassed and the
# `data` variable is used but not initialized)
curl -I "http://localhost:3000/weather/washington"
```
115 changes: 95 additions & 20 deletions examples/sanic/main.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,124 @@
import json
import pybrake
from contextvars import ContextVar
from datetime import *

import requests
from pybrake.middleware.sanic import init_app
from sanic import Sanic
from sanic import response
from sqlalchemy import INTEGER, Column, String, select, insert
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import sessionmaker

app = Sanic("WeatherDetails")
app = Sanic(__name__)

notifier = pybrake.Notifier(project_id=999999,
project_key='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
environment='production')
bind = create_async_engine("sqlite+aiosqlite:///./test.db", echo=True)
Base = declarative_base()

city_list = ["pune", "austin", "santabarbara"]
app.config["PYBRAKE"] = dict(
project_id=9999,
project_key="xxxxxxxxxxxxxxxxxxxxxxxxx",
environment="test",
performance_stats=True, # False to disable APM
)

_base_model_session_ctx = ContextVar("session")

app = init_app(app, bind)


@app.middleware("request")
async def inject_session(request):
request.ctx.session = sessionmaker(bind, AsyncSession,
expire_on_commit=False)()
request.ctx.session_ctx_token = _base_model_session_ctx.set(
request.ctx.session)


@app.middleware("response")
async def close_session(request, response):
if hasattr(request.ctx, "session_ctx_token"):
_base_model_session_ctx.reset(request.ctx.session_ctx_token)
await request.ctx.session.close()


def setup_database():
@app.listener('after_server_start')
async def connect_to_db(*args, **kwargs):
async with bind.begin() as conn:
await conn.run_sync(Base.metadata.create_all)

@app.listener('after_server_stop')
async def disconnect_from_db(*args, **kwargs):
async with bind.begin() as conn:
await conn.close()


class User(Base):
__tablename__ = "user"

id = Column(INTEGER, primary_key=True)
username = Column(String(80), unique=True, nullable=False)
email = Column(String(120), unique=True, nullable=False)

def __repr__(self):
return "<User %r>" % self.username


city_list = ["pune", "austin", "santabarbara", "washington"]


# API for Hello Application
@app.route("/")
def run(request):
return response.text("Hello, Welcome to the Weather App !")
async def run(request):
session = request.ctx.session
async with session.begin():
stmt = select(User)
result = await session.execute(stmt)
res = result.scalar()
if not res:
stmt = insert(User).values(username="test", email="[email protected]")
await session.execute(stmt)
return response.html("""
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0"/>
<title>Cherrypy Weather App</title>
</head>
<body>
<H1>Hello, Welcome to Cherrypy Weather App.</H1>
</body>
</html>
""")


# API for current server date
@app.route("date")
def getdate(request):
current_datetime = datetime.now()
return response.text(f"Current date and time is: {current_datetime}")
return response.json({
'date': "Current Date and Time is: %s" % datetime.now()
})


# API for location details
@app.route("locations")
def get_location_details(request):
return response.text(" ".join(city_list))
return response.json({'locations': city_list})


# API for weather details for a location
@app.route("/weather/<location_name>")
def get_weather_details(request, location_name):
file_name = location_name + ".json"
if location_name in city_list:
with open('static/' + file_name) as f:
data = json.load(f)
return data
return "404 Error: Page not Found"

if location_name not in city_list:
raise response.json({'error': 'Location not found!'}, 400)
with requests.get(
'https://airbrake.github.io/weatherapi/weather/' + location_name) as f:
return response.json(f.json())


# debug logs enabled with debug = True
app.run(host="0.0.0.0", port=3000, debug=True)
if __name__ == "__main__":
setup_database()
app.run(host="0.0.0.0", port=3000, debug=True, auto_reload=True)
14 changes: 13 additions & 1 deletion examples/sanic/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
aiofiles==0.8.0
aiosqlite==0.17.0
asgiref==3.4.1
certifi==2021.10.8
charset-normalizer==2.0.9
coreapi==2.3.3
coreschema==0.0.4
greenlet==1.1.2
httptools==0.4.0
idna==3.3
itypes==1.2.0
Jinja2==3.0.3
MarkupSafe==2.0.1
multidict==5.2.0
openapi-codec==1.3.2
panda==0.3.1
pybrake
python-oauth2==1.1.1
pytz==2021.3
pyudorandom==1.0.0
PyYAML==5.1
requests==2.26.0
sanic==21.12.0
sanic-routing==0.7.2
simplejson==3.17.6
SQLAlchemy==1.4.36
sqlparse==0.4.2
typing_extensions==4.2.0
ujson==5.3.0
uritemplate==4.1.1
urllib3==1.26.7ß
urllib3==1.26.7
uvloop==0.16.0
websockets==10.3
Loading

0 comments on commit 15ea50a

Please sign in to comment.