Initial commit
commit
3e2cf37921
@ -0,0 +1,62 @@
|
|||||||
|
# Pycharm
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# ---> Python
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
@ -0,0 +1,52 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from apistar import Include, Route, http, Response, annotate
|
||||||
|
from apistar.frameworks.wsgi import WSGIApp as App
|
||||||
|
from apistar.handlers import docs_urls, static_urls
|
||||||
|
from apistar.backends import sqlalchemy_backend
|
||||||
|
from apistar.backends.sqlalchemy_backend import Session
|
||||||
|
|
||||||
|
from models import Base, Cookie
|
||||||
|
from model.util import alchemyencoder
|
||||||
|
from render import JSONRenderer
|
||||||
|
|
||||||
|
|
||||||
|
def welcome(name=None):
|
||||||
|
if name is None:
|
||||||
|
return {'message': 'Welcome to API Star!'}
|
||||||
|
return {'message': 'Welcome to API Star, %s!' % name}
|
||||||
|
|
||||||
|
|
||||||
|
@annotate(renderers=[JSONRenderer()])
|
||||||
|
def get_cookies(session: Session):
|
||||||
|
cookies = session.query(Cookie).all()
|
||||||
|
result = [{"id": cookie.id,
|
||||||
|
"created_date": cookie.created_date,
|
||||||
|
"modified_date": cookie.modified_date,
|
||||||
|
"name": cookie.name,
|
||||||
|
"recipe_url": cookie.recipe_url,
|
||||||
|
"sku": cookie.sku,
|
||||||
|
"qoh": cookie.unit_cost}
|
||||||
|
for cookie in cookies]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
routes = [
|
||||||
|
Route('/', 'GET', welcome),
|
||||||
|
Route('/cookies', 'GET', get_cookies),
|
||||||
|
Include('/docs', docs_urls),
|
||||||
|
Include('/static', static_urls)
|
||||||
|
]
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
'DATABASE': {
|
||||||
|
'URL': 'postgresql://:@localhost/apistar',
|
||||||
|
'METADATA': Base.metadata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app = App(routes=routes,
|
||||||
|
settings=settings,
|
||||||
|
commands=sqlalchemy_backend.commands,
|
||||||
|
components=sqlalchemy_backend.components
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
import datetime as dt
|
||||||
|
import decimal
|
||||||
|
|
||||||
|
def alchemyencoder(obj):
|
||||||
|
"""JSON encoder function for SQLAlchemy special classes."""
|
||||||
|
if isinstance(obj, dt.datetime):
|
||||||
|
return obj.isoformat()
|
||||||
|
elif isinstance(obj, decimal.Decimal):
|
||||||
|
return float(obj)
|
@ -0,0 +1,70 @@
|
|||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, Boolean, Numeric
|
||||||
|
from sqlalchemy.orm import relationship, backref
|
||||||
|
from sqlalchemy.sql import expression
|
||||||
|
from sqlalchemy.ext.compiler import compiles
|
||||||
|
from sqlalchemy.types import DateTime as DateTimeType
|
||||||
|
|
||||||
|
# can be moved to models util
|
||||||
|
class utcnow(expression.FunctionElement):
|
||||||
|
type = DateTimeType()
|
||||||
|
|
||||||
|
# Can be moved to the models util dirp
|
||||||
|
@compiles(utcnow, 'postgresql')
|
||||||
|
def pg_utcnow(element, compiler, **kw):
|
||||||
|
return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
|
||||||
|
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DBMixin:
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
created_date = Column(DateTime, server_default=utcnow())
|
||||||
|
modified_date = Column(DateTime, server_default=utcnow(), onupdate=utcnow())
|
||||||
|
|
||||||
|
|
||||||
|
def ReferenceCol(tablename, nullable=False, **kw):
|
||||||
|
return Column(ForeignKey('{}.id'.format(tablename)), nullable=nullable, **kw)
|
||||||
|
|
||||||
|
|
||||||
|
class Cookie(Base, DBMixin):
|
||||||
|
__tablename__ = 'cookies'
|
||||||
|
|
||||||
|
name = Column(String(50), index=True)
|
||||||
|
recipe_url = Column(String(255))
|
||||||
|
sku = Column(String(55))
|
||||||
|
qoh = Column(Integer)
|
||||||
|
unit_cost = Column(Numeric(12, 2))
|
||||||
|
|
||||||
|
|
||||||
|
class User(DBMixin, Base):
|
||||||
|
__tablename__ = 'users'
|
||||||
|
|
||||||
|
username = Column(String(255), nullable=False, unique=True)
|
||||||
|
email_address = Column(String(255), nullable=False)
|
||||||
|
phone = Column(String(20), nullable=False)
|
||||||
|
password = Column(String(255))
|
||||||
|
|
||||||
|
|
||||||
|
class Order(DBMixin, Base):
|
||||||
|
__tablename__ = 'orders'
|
||||||
|
|
||||||
|
user_id = ReferenceCol('users')
|
||||||
|
shipped = Column(Boolean, default=False)
|
||||||
|
|
||||||
|
user = relationship('User', backref=backref('orders'))
|
||||||
|
|
||||||
|
|
||||||
|
class LineItem(DBMixin, Base):
|
||||||
|
__tablename__ = 'line_items'
|
||||||
|
|
||||||
|
order_id = ReferenceCol('orders')
|
||||||
|
cookie_id = ReferenceCol('cookies')
|
||||||
|
quantity = Column(Integer)
|
||||||
|
extended_cost = Column(Numeric(12, 2))
|
||||||
|
|
||||||
|
order = relationship('Order', backref=backref('line_items'))
|
||||||
|
cookie = relationship('Cookie', uselist=False)
|
||||||
|
|
@ -0,0 +1,13 @@
|
|||||||
|
import json
|
||||||
|
from apistar import http
|
||||||
|
from apistar.renderers import Renderer
|
||||||
|
|
||||||
|
from model.util import alchemyencoder
|
||||||
|
|
||||||
|
|
||||||
|
class JSONRenderer(Renderer):
|
||||||
|
media_type = 'application/json'
|
||||||
|
charset = None
|
||||||
|
|
||||||
|
def render(self, data: http.ResponseData) -> bytes:
|
||||||
|
return json.dumps(data, default=alchemyencoder).encode('utf-8')
|
@ -0,0 +1,17 @@
|
|||||||
|
apistar==0.3.6
|
||||||
|
certifi==2017.7.27.1
|
||||||
|
chardet==3.0.4
|
||||||
|
coreapi==2.3.1
|
||||||
|
coreschema==0.0.4
|
||||||
|
idna==2.6
|
||||||
|
itypes==1.1.0
|
||||||
|
Jinja2==2.9.6
|
||||||
|
MarkupSafe==1.0
|
||||||
|
py==1.4.34
|
||||||
|
pytest==3.2.2
|
||||||
|
requests==2.18.4
|
||||||
|
SQLAlchemy==1.1.14
|
||||||
|
uritemplate==3.0.0
|
||||||
|
urllib3==1.22
|
||||||
|
Werkzeug==0.12.2
|
||||||
|
whitenoise==3.3.1
|
@ -0,0 +1,20 @@
|
|||||||
|
from apistar.test import TestClient
|
||||||
|
from app import welcome
|
||||||
|
|
||||||
|
|
||||||
|
def test_welcome():
|
||||||
|
"""
|
||||||
|
Testing a view directly.
|
||||||
|
"""
|
||||||
|
data = welcome()
|
||||||
|
assert data == {'message': 'Welcome to API Star!'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_http_request():
|
||||||
|
"""
|
||||||
|
Testing a view, using the test client.
|
||||||
|
"""
|
||||||
|
client = TestClient()
|
||||||
|
response = client.get('http://localhost/')
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {'message': 'Welcome to API Star!'}
|
Loading…
Reference in New Issue