-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IMP] sample example based on middleware
- Loading branch information
Showing
6 changed files
with
167 additions
and
5,183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.